|
|
|
|
|
在一些商品展示的網(wǎng)頁(yè)里,我們經(jīng)??吹綀D片放大的效果。這個(gè)效果非常好,可以讓人看清圖片物品的細(xì)節(jié)。本文就給大家介紹一下,如何用純JS來(lái)實(shí)現(xiàn)這個(gè)功能。
功能簡(jiǎn)介
鼠標(biāo)移到圖片上時(shí),圖片的鼠標(biāo)位置放大顯示。
實(shí)現(xiàn)方法,純JavaScript實(shí)現(xiàn)。
HTML代碼
<section class="c-container" data-image-magnifier>
<img src="s-1.jpg" id="test-img" class="c-container__img" srcset="s-1.jpg 480w, b-1.jpg 1200w, b-2.jpg 2000w" sizes="100vw" data-magnifier-size="4000px" alt="壁畫(huà)照片" />
</section>
說(shuō)明:
標(biāo)簽元素是section
,c-container
是類名,data-image-magnifier
是元素的屬性,JS代碼將通過(guò)該名稱定位到該元素標(biāo)簽。
s-1.jpg
是圖片原圖,寬度為500px;b-1.jpg
是大圖,寬度為1000px;b-2.jpg
是大圖,寬度為2000px。
JavaScript代碼
<script>
;(function () {
"use strict";
const ENLARGE_IMG_CONTAINER_ATTR = "data-image-magnifier";
const imgMagnifierContainers = Array.from(document.querySelectorAll("[" + ENLARGE_IMG_CONTAINER_ATTR + "]"));
if (!imgMagnifierContainers.length) {
console.error("None element with " + ENLARGE_IMG_CONTAINER_ATTR + " attribute has been found.");
return;
};
// Classes for JS hooks
const IMAGE_MAGNIFIER_IMAGE_JS_CLASS = "js-magnifierImg";
const LOUPE_WRAPPER_JS_CLASS = "js-flyoutLoupe";
const LOUPE_IMAGE_JS_CLASS = "js-flyoutLoupeImg";
// Classes for the Style
const IMAGE_MAGNIFIER_CLASS = "c-image-magnifier";
const IMAGE_MAGNIFIER_IMAGE_CLASS = "c-image-magnifier__image";
const LOUPE_WRAPPER_CLASS = "o-loupe-wrapper";
const LOUPE_IMAGE_CLASS = "o-loupe-wrapper__image";
/// this attribute determines the value of the `size` attribute on generated loupe-image
const LOUPE_IMAGE_SIZE_ATTR = "data-magnifier-size";
/* ADDING EVENT LISTENERS
-------------------------------------*/
document.addEventListener("DOMContentLoaded", onDOMContentLoaded);
/*========================================
EVENT LISTENERS
==========================================*/
function onDOMContentLoaded(e) {// TODO: this event may be changed into public init method
imgMagnifierContainers.forEach(function (container) {
container.imgMagnifier = {
touchStarted: false };
container.addEventListener("mouseenter", imageContainerOnMouseEnter);
container.classList.add(IMAGE_MAGNIFIER_CLASS);
const magnifierImg = setupMagnifierImg(container, IMAGE_MAGNIFIER_IMAGE_JS_CLASS, IMAGE_MAGNIFIER_IMAGE_CLASS);
container.addEventListener("touchstart", imageContainerOnMouseEnter);
container.addEventListener("touchmove", imageContainerOnMouseMove);
container.addEventListener("touchend", imageContainerOnMouseLeave);
container.addEventListener("mousemove", imageContainerOnMouseMove);
const loupeHTML = _createLoupeImgHTML(container, IMAGE_MAGNIFIER_IMAGE_JS_CLASS);
container.appendChild(loupeHTML);
});
};
function imageContainerOnMouseEnter(e) {
const container = e.currentTarget;
// mouse events may fire along with touch events and we just want the touch event
if (container.imgMagnifier.touchStarted && e.type === "mouseenter") {
return;
}
const isTouchEvent = e.type === "touchstart";
if (isTouchEvent) {
container.imgMagnifier.touchStarted = true;
};
const loupeImage = container.querySelector("." + LOUPE_IMAGE_JS_CLASS);
const loupeWrapper = container.querySelector("." + LOUPE_WRAPPER_JS_CLASS);
if (loupeImage) {
const loupeImageSize = loupeImage.getAttribute(LOUPE_IMAGE_SIZE_ATTR);
if (loupeImageSize)
loupeImage.setAttribute("sizes", loupeImageSize);
};
// offset the loupe a bit differently for touch event so that it's not directly beneath a finger
const divider = isTouchEvent ? 1.1 : 2;
loupeWrapper.style.marginLeft = loupeWrapper.offsetWidth / divider * -1 + "px";
loupeWrapper.style.marginTop = loupeWrapper.offsetHeight / divider * -1 + "px";
};
function imageContainerOnMouseMove(e) {
debugger;
const imageContainer = e.currentTarget; // refers to the element event handler has been attached to
// mouse events may fire along with touch events and we just want the touch event
if (imageContainer.imgMagnifier.touchStarted && e.type === "mousemove") {
return;
};
const isTouchEvent = e.type === "touchmove";
// const moveX = isTouchEvent ? e.changedTouches[0].pageX : e.clientX;
// const moveY = isTouchEvent ? e.changedTouches[0].pageY : e.clientY;
const moveX = isTouchEvent ? e.touches[0].clientX : e.clientX;
const moveY = isTouchEvent ? e.touches[0].clientY : e.clientY;
const loupeWrapper = imageContainer.querySelector("." + LOUPE_WRAPPER_JS_CLASS);
const loupeImage = loupeWrapper.querySelector("." + LOUPE_IMAGE_JS_CLASS);
const x = moveX - imageContainer.getBoundingClientRect().left;
const y = moveY - imageContainer.getBoundingClientRect().top;
const containerWidth = imageContainer.offsetWidth;
const containerHeight = imageContainer.offsetHeight;
const loupeImageWidth = loupeImage.offsetWidth;
const loupeImageHeight = loupeImage.offsetHeight;
const loupeWrapperWidth = loupeWrapper.offsetWidth;
const loupeWrapperHeight = loupeWrapper.offsetHeight;
const widthFactor = containerWidth / loupeWrapperWidth;
const heightFactor = containerWidth / loupeWrapperHeight;
requestAnimationFrame(function () {
loupeWrapper.style.top = y + "px";
loupeWrapper.style.left = x + "px";
loupeWrapper.scrollLeft = x / containerWidth * (loupeImageWidth - loupeWrapperWidth);
loupeWrapper.scrollTop = y / containerHeight * (loupeImageHeight - loupeWrapperHeight);
});
};
function imageContainerOnMouseLeave(e) {
const container = e.currentTarget;
if (container.imgMagnifier.touchStarted) {
container.imgMagnifier.touchStarted = false;
};
};
/*-----------------------------------------
UTILITY FUNCTIONS
-------------------------------------------*/
function _createLoupeImgHTML(container, imgClass) {
const loupeContainer = document.createElement("div");
const origIMG = container.querySelector("." + imgClass);
debugger;
const loupeImg = origIMG ? origIMG.cloneNode() : null;
loupeContainer.classList.add(LOUPE_WRAPPER_CLASS, LOUPE_WRAPPER_JS_CLASS);
if (loupeImg) {
loupeImg.removeAttribute("id");
loupeImg.className = LOUPE_IMAGE_CLASS;
loupeImg.classList.add(LOUPE_IMAGE_JS_CLASS);
loupeContainer.appendChild(loupeImg);
}
return loupeContainer;
};
function setupMagnifierImg(imgContainer, imgJSClass, imgStyleClass) {
const img = imgContainer.querySelector("img");
if (!img) throw new Error("Image Magnifier: Image was not found");
img.classList.add(imgStyleClass, imgJSClass);
return img;
};
})();
</script>
CSS代碼
HTML {
/*using system font-stack*/
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
font-size: 115%; /*~18px*/
font-size: calc(16px + (30 - 16) * (100vw - 300px) / (1300 - 300) );
line-height: 1.5;
box-sizing: border-box;
}
BODY {
margin: 0;
color: #3a3d40;
background: rgb(253, 254, 253);
}
*, *::before, *::after {
box-sizing: inherit;
color: inherit;
}
/*Actual Style*/
.c-container {
position: relative;
margin: 8rem auto;
max-width: 1000px;
cursor: none;
}
.c-container__img {
width: 100%;
}
.c-image-magnifier__image {
-webkit-touch-callout:none;
-webkit-user-select:none;
user-select: none;
}
.o-loupe-wrapper {
position: absolute;
width: 9.45rem; /*~150px*/
height: 9.45rem; /*~150px*/
/*max-width: 18.45rem;*/ /*~300px*/
/*max-height: 18.45rem;*/ /*~300px*/
border-radius: 100%;
border: 5px solid #fff;
overflow: hidden;
pointer-events: none;
transform: scale(0);
opacity: 0;
transition: opacity 0s .15s, transform .3s ease-out;
box-shadow: 0 5px 7px rgba(0, 0, 0, .7);
z-index: 999;
}
[data-image-magnifier]:hover .o-loupe-wrapper {
transform: scale(1);
opacity: 1;
transition-timing-function: ease-in;
}
.o-loupe-wrapper__image {
}
總結(jié)
本文介紹了純JS實(shí)現(xiàn)圖片放大鏡效果的方法。比較實(shí)用,并且遷移使用方便,值得收藏。