아래 HTML 소스 코드를 활용하면 상품 상세 대표 이미지에 마우스를 호버할 때 확대 효과를 적용할 수 있어요.
•
데스크톱: 커서가 대표 이미지에 호버되었을 때 작동합니다.
•
모바일: 대표 이미지에 터치하면 터치한 영역이 확대됩니다.
•
코드 상에서 let scaleValue = 2.5; 의 숫자를 조정하여 배율을 변경할 수 있습니다.
•
페이지 오른쪽의 목차를 눌러 해당 테마로 바로 이동하면 편리합니다.
상품 상세 대표 이미지 확대하기
Essential 테마
<script>
(() => {
const script = document.createElement("script");
script.innerHTML = `
(() => {
const applyZoomEffect = (image) => {
if (!image) return;
image.removeEventListener("mouseenter", image._mouseenterHandler);
image.removeEventListener("mouseleave", image._mouseleaveHandler);
image.removeEventListener("mousemove", image._mousemoveHandler);
image.removeEventListener("touchstart", image._touchstartHandler);
image.removeEventListener("touchmove", image._touchmoveHandler);
image.removeEventListener("touchend", image._touchendHandler);
let isHovered = false;
let isZoomed = false;
let scaleValue = 2.5; // 이 값은 확대 배율을 조정합니다. 원하는 배율로 변경해 주세요.
let startX = 0, startY = 0, moveX = 0, moveY = 0;
let touchMoved = false;
let isHorizontalSwipe = false;
image.style.transform = "scale(1)";
image.style.transition = "none";
image._mouseenterHandler = () => {
isHovered = true;
image.style.transform = \`scale(\${scaleValue})\`;
image.style.transition = "transform 0.2s ease-out";
};
image._mouseleaveHandler = () => {
isHovered = false;
image.style.transform = "scale(1)";
image.style.transition = "transform 0.1s ease-in-out";
};
image._mousemoveHandler = (e) => {
if (!isHovered) return;
const rect = image.getBoundingClientRect();
const relativeX = ((e.clientX - rect.left) / rect.width * 100).toFixed(2);
const relativeY = ((e.clientY - rect.top) / rect.height * 100).toFixed(2);
image.style.transformOrigin = \`\${relativeX}% \${relativeY}%\`;
};
image._touchstartHandler = (e) => {
e.stopPropagation();
touchMoved = false;
isHorizontalSwipe = false;
startX = e.touches[0].clientX;
startY = e.touches[0].clientY;
};
image._touchmoveHandler = (e) => {
const deltaX = Math.abs(e.touches[0].clientX - startX);
const deltaY = Math.abs(e.touches[0].clientY - startY);
if (deltaX > 10) {
isHorizontalSwipe = true;
}
if (isHorizontalSwipe) {
e.preventDefault();
}
if (deltaX > 10 || deltaY > 10) {
touchMoved = true;
}
};
image._touchendHandler = (e) => {
if (touchMoved) return;
if (isZoomed) {
isZoomed = false;
image.style.transform = "scale(1)";
image.style.transition = "transform 0.1s ease-in-out";
} else {
isZoomed = true;
const rect = image.getBoundingClientRect();
const touchX = e.changedTouches[0].clientX;
const touchY = e.changedTouches[0].clientY;
const relativeX = ((touchX - rect.left) / rect.width * 100).toFixed(2);
const relativeY = ((touchY - rect.top) / rect.height * 100).toFixed(2);
image.style.transformOrigin = \`\${relativeX}% \${relativeY}%\`;
image.style.transform = \`scale(\${scaleValue})\`;
image.style.transition = "transform 0.2s ease-out";
}
};
image.addEventListener("mouseenter", image._mouseenterHandler);
image.addEventListener("mouseleave", image._mouseleaveHandler);
image.addEventListener("mousemove", image._mousemoveHandler);
image.addEventListener("touchstart", image._touchstartHandler);
image.addEventListener("touchmove", image._touchmoveHandler, { passive: false });
image.addEventListener("touchend", image._touchendHandler);
};
const targetImageSelector = "[class*='ProductRequiredInfoThumbnail_wrapper__'] > :not(.swiper-watch-progress) [class*='ProductImage_image-wrapper'] img";
const initialImageList = document.querySelectorAll(targetImageSelector);
initialImageList.forEach((initialImage) => {
applyZoomEffect(initialImage);
});
const observeMainImage = () => {
let attempts = 0;
const checkImage = setInterval(() => {
const updatedImageList = document.querySelectorAll(targetImageSelector);
if (updatedImageList.length > 0) {
updatedImageList.forEach((updatedImage) => {
applyZoomEffect(updatedImage);
});
clearInterval(checkImage);
}
attempts++;
if (attempts > 50) {
clearInterval(checkImage);
}
}, 15);
};
const observer = new MutationObserver(() => {
observeMainImage();
});
observer.observe(document.body, { childList: true, subtree: true });
})();
`;
document.body.appendChild(script);
})();
</script>
JavaScript
복사
Grid 테마
<script>
(() => {
const script = document.createElement("script");
script.innerHTML = `
(() => {
const applyZoomEffect = (image) => {
if (!image) return;
image.removeEventListener("mouseenter", image._mouseenterHandler);
image.removeEventListener("mouseleave", image._mouseleaveHandler);
image.removeEventListener("mousemove", image._mousemoveHandler);
image.removeEventListener("touchstart", image._touchstartHandler);
image.removeEventListener("touchmove", image._touchmoveHandler);
image.removeEventListener("touchend", image._touchendHandler);
let isHovered = false;
let isZoomed = false;
let scaleValue = 2.5; // 이 값은 확대 배율을 조정합니다. 원하는 배율로 변경해 주세요.
let startX = 0, startY = 0, moveX = 0, moveY = 0;
let touchMoved = false;
let isHorizontalSwipe = false;
image.style.transform = "scale(1)";
image.style.transition = "none";
image._mouseenterHandler = () => {
isHovered = true;
image.style.transform = \`scale(\${scaleValue})\`;
image.style.transition = "transform 0.2s ease-out";
};
image._mouseleaveHandler = () => {
isHovered = false;
image.style.transform = "scale(1)";
image.style.transition = "transform 0.1s ease-in-out";
};
image._mousemoveHandler = (e) => {
if (!isHovered) return;
const rect = image.getBoundingClientRect();
const relativeX = ((e.clientX - rect.left) / rect.width * 100).toFixed(2);
const relativeY = ((e.clientY - rect.top) / rect.height * 100).toFixed(2);
image.style.transformOrigin = \`\${relativeX}% \${relativeY}%\`;
};
image._touchstartHandler = (e) => {
e.stopPropagation();
touchMoved = false;
isHorizontalSwipe = false;
startX = e.touches[0].clientX;
startY = e.touches[0].clientY;
};
image._touchmoveHandler = (e) => {
const deltaX = Math.abs(e.touches[0].clientX - startX);
const deltaY = Math.abs(e.touches[0].clientY - startY);
if (deltaX > 10) {
isHorizontalSwipe = true;
}
if (isHorizontalSwipe) {
e.preventDefault();
}
if (deltaX > 10 || deltaY > 10) {
touchMoved = true;
}
};
image._touchendHandler = (e) => {
if (touchMoved) return;
if (isZoomed) {
isZoomed = false;
image.style.transform = "scale(1)";
image.style.transition = "transform 0.1s ease-in-out";
} else {
isZoomed = true;
const rect = image.getBoundingClientRect();
const touchX = e.changedTouches[0].clientX;
const touchY = e.changedTouches[0].clientY;
const relativeX = ((touchX - rect.left) / rect.width * 100).toFixed(2);
const relativeY = ((touchY - rect.top) / rect.height * 100).toFixed(2);
image.style.transformOrigin = \`\${relativeX}% \${relativeY}%\`;
image.style.transform = \`scale(\${scaleValue})\`;
image.style.transition = "transform 0.2s ease-out";
}
};
image.addEventListener("mouseenter", image._mouseenterHandler);
image.addEventListener("mouseleave", image._mouseleaveHandler);
image.addEventListener("mousemove", image._mousemoveHandler);
image.addEventListener("touchstart", image._touchstartHandler);
image.addEventListener("touchmove", image._touchmoveHandler, { passive: false });
image.addEventListener("touchend", image._touchendHandler);
};
const targetImageSelector = "[class*='ProductRequiredInfo_image-panel__'] img:not([class*='ProductRequiredInfoThumbnail_thumb__'] img)";
const initialImageList = document.querySelectorAll(targetImageSelector);
initialImageList.forEach((initialImage) => {
applyZoomEffect(initialImage);
});
const observeMainImage = () => {
let attempts = 0;
const checkImage = setInterval(() => {
const updatedImageList = document.querySelectorAll(targetImageSelector);
if (updatedImageList.length > 0) {
updatedImageList.forEach((updatedImage) => {
applyZoomEffect(updatedImage);
});
clearInterval(checkImage);
}
attempts++;
if (attempts > 50) {
clearInterval(checkImage);
}
}, 15);
};
const observer = new MutationObserver(() => {
observeMainImage();
});
observer.observe(document.body, { childList: true, subtree: true });
})();
`;
document.body.appendChild(script);
})();
</script>
JavaScript
복사
Round 테마
<script>
(() => {
const script = document.createElement("script");
script.innerHTML = `
(() => {
const applyZoomEffect = (image) => {
if (!image) return;
image.removeEventListener("mouseenter", image._mouseenterHandler);
image.removeEventListener("mouseleave", image._mouseleaveHandler);
image.removeEventListener("mousemove", image._mousemoveHandler);
image.removeEventListener("touchstart", image._touchstartHandler);
image.removeEventListener("touchmove", image._touchmoveHandler);
image.removeEventListener("touchend", image._touchendHandler);
let isHovered = false;
let isZoomed = false;
let scaleValue = 2.5; // 이 값은 확대 배율을 조정합니다. 원하는 배율로 변경해 주세요.
let startX = 0, startY = 0, moveX = 0, moveY = 0;
let touchMoved = false;
let isHorizontalSwipe = false;
image.style.transform = "scale(1)";
image.style.transition = "none";
image._mouseenterHandler = () => {
isHovered = true;
image.style.transform = \`scale(\${scaleValue})\`;
image.style.transition = "transform 0.2s ease-out";
};
image._mouseleaveHandler = () => {
isHovered = false;
image.style.transform = "scale(1)";
image.style.transition = "transform 0.1s ease-in-out";
};
image._mousemoveHandler = (e) => {
if (!isHovered) return;
const rect = image.getBoundingClientRect();
const relativeX = ((e.clientX - rect.left) / rect.width * 100).toFixed(2);
const relativeY = ((e.clientY - rect.top) / rect.height * 100).toFixed(2);
image.style.transformOrigin = \`\${relativeX}% \${relativeY}%\`;
};
image._touchstartHandler = (e) => {
e.stopPropagation();
touchMoved = false;
isHorizontalSwipe = false;
startX = e.touches[0].clientX;
startY = e.touches[0].clientY;
};
image._touchmoveHandler = (e) => {
const deltaX = Math.abs(e.touches[0].clientX - startX);
const deltaY = Math.abs(e.touches[0].clientY - startY);
if (deltaX > 10) {
isHorizontalSwipe = true;
}
if (isHorizontalSwipe) {
e.preventDefault();
}
if (deltaX > 10 || deltaY > 10) {
touchMoved = true;
}
};
image._touchendHandler = (e) => {
if (touchMoved) return;
if (isZoomed) {
isZoomed = false;
image.style.transform = "scale(1)";
image.style.transition = "transform 0.1s ease-in-out";
} else {
isZoomed = true;
const rect = image.getBoundingClientRect();
const touchX = e.changedTouches[0].clientX;
const touchY = e.changedTouches[0].clientY;
const relativeX = ((touchX - rect.left) / rect.width * 100).toFixed(2);
const relativeY = ((touchY - rect.top) / rect.height * 100).toFixed(2);
image.style.transformOrigin = \`\${relativeX}% \${relativeY}%\`;
image.style.transform = \`scale(\${scaleValue})\`;
image.style.transition = "transform 0.2s ease-out";
}
};
image.addEventListener("mouseenter", image._mouseenterHandler);
image.addEventListener("mouseleave", image._mouseleaveHandler);
image.addEventListener("mousemove", image._mousemoveHandler);
image.addEventListener("touchstart", image._touchstartHandler);
image.addEventListener("touchmove", image._touchmoveHandler, { passive: false });
image.addEventListener("touchend", image._touchendHandler);
};
const targetImageSelector = "[class*='ProductImage_swiper-item-wrapper__'] img";
const initialImageList = document.querySelectorAll(targetImageSelector);
initialImageList.forEach((initialImage) => {
applyZoomEffect(initialImage);
});
const observeMainImage = () => {
let attempts = 0;
const checkImage = setInterval(() => {
const updatedImageList = document.querySelectorAll(targetImageSelector);
if (updatedImageList.length > 0) {
updatedImageList.forEach((updatedImage) => {
applyZoomEffect(updatedImage);
});
clearInterval(checkImage);
}
attempts++;
if (attempts > 50) {
clearInterval(checkImage);
}
}, 15);
};
const observer = new MutationObserver(() => {
observeMainImage();
});
observer.observe(document.body, { childList: true, subtree: true });
})();
`;
document.body.appendChild(script);
})();
</script>
JavaScript
복사
상품 상세 대표 이미지 옆에서 확대하기
Essential 테마
<script>
(() => {
const script = document.createElement("script");
script.innerHTML = `
(() => {
const applyZoomEffect = (image) => {
if (!image) return;
image.removeEventListener("mouseenter", image._mouseenterHandler);
image.removeEventListener("mouseleave", image._mouseleaveHandler);
image.removeEventListener("mousemove", image._mousemoveHandler);
image.removeEventListener("touchstart", image._touchstartHandler);
image.removeEventListener("touchmove", image._touchmoveHandler);
image.removeEventListener("touchend", image._touchendHandler);
let scaleValue = 2.5; // 이 값은 확대 배율을 조정합니다. 원하는 배율로 변경해 주세요.
let isZoomed = false;
let zoomPanel = document.querySelector("[class*='ProductRequiredInfostyled__ProductRequiredInfo']");
let thumbnailWrapper = document.querySelector("[class*='ProductRequiredInfoThumbnail_wrapper']");
let animationFrameId = null;
let touchStartX = 0;
let touchMoved = false;
if (!zoomPanel || !thumbnailWrapper) return;
zoomPanel.style.position = "relative";
zoomPanel.style.overflow = "hidden";
let cursorParent = image.closest("[class*='ProductRequiredInfoThumbnail_wrapper__'] .swiper:not([class*='ProductRequiredInfoThumbnail_thumb']) [class*='ProductImage_image-wrapper']");
if (!cursorParent) return;
let cursorBox = cursorParent.querySelector(".cursor-box");
if (!cursorBox) {
cursorBox = document.createElement("div");
cursorBox.classList.add("cursor-box");
cursorBox.style.position = "absolute";
cursorBox.style.width = "100px";
cursorBox.style.height = "100px";
cursorBox.style.border = "1px solid rgba(255, 255, 255, 0.3)";
cursorBox.style.background = "rgba(255, 255, 255, 0.2)";
cursorBox.style.borderRadius = "50%";
cursorBox.style.pointerEvents = "none";
cursorBox.style.display = "none";
cursorParent.appendChild(cursorBox);
}
if (window.innerWidth <= 768) {
image._touchstartHandler = (e) => {
touchStartX = e.touches[0].clientX;
touchMoved = false;
};
image._touchmoveHandler = (e) => {
let deltaX = Math.abs(e.touches[0].clientX - touchStartX);
if (deltaX > 10) {
touchMoved = true;
}
};
image._touchendHandler = (e) => {
if (touchMoved) return;
e.stopPropagation();
if (isZoomed) {
isZoomed = false;
image.style.transition = "transform 0.2s ease-in-out";
image.style.transform = "scale(1)";
} else {
isZoomed = true;
const rect = image.getBoundingClientRect();
const touchX = ((e.changedTouches[0].clientX - rect.left) / rect.width) * 100;
const touchY = ((e.changedTouches[0].clientY - rect.top) / rect.height) * 100;
image.style.transition = "transform 0.2s ease-out";
image.style.transformOrigin = \`\${touchX}% \${touchY}%\`;
image.style.transform = \`scale(\${scaleValue})\`;
}
};
image.addEventListener("touchstart", image._touchstartHandler);
image.addEventListener("touchmove", image._touchmoveHandler);
image.addEventListener("touchend", image._touchendHandler);
return;
}
image._mouseenterHandler = () => {
let existingZoomContainer = zoomPanel.querySelector(".zoom-container");
if (existingZoomContainer) return;
let thumbnailWidth = thumbnailWrapper.clientWidth;
zoomPanel.style.maxWidth = \`calc(100% - \${thumbnailWidth + 50}px)\`;
const rect = image.getBoundingClientRect();
const aspectRatio = rect.width / rect.height;
let zoomContainer = document.createElement("div");
zoomContainer.classList.add("zoom-container");
zoomContainer.style.position = "absolute";
zoomContainer.style.width = "100%";
zoomContainer.style.height = "auto";
zoomContainer.style.aspectRatio = \`\${aspectRatio}\`;
zoomContainer.style.left = "50%";
zoomContainer.style.top = "0";
zoomContainer.style.transform = "translate(-50%, 0%)";
zoomContainer.style.overflow = "hidden";
zoomContainer.style.pointerEvents = "none";
let zoomedImage = image.cloneNode(true);
zoomedImage.classList.add("zoomed");
zoomedImage.style.position = "absolute";
zoomedImage.style.width = "100%";
zoomedImage.style.height = "100%";
zoomedImage.style.left = "50%";
zoomedImage.style.top = "0";
zoomedImage.style.transform = "translate(-50%, 0%) scale(1)";
zoomContainer.appendChild(zoomedImage);
zoomPanel.appendChild(zoomContainer);
cursorBox.style.display = "block";
};
let lastMoveTime = 0;
image._mousemoveHandler = (e) => {
const now = performance.now();
if (now - lastMoveTime < 16) return;
lastMoveTime = now;
if (animationFrameId) {
cancelAnimationFrame(animationFrameId);
}
animationFrameId = requestAnimationFrame(() => {
let zoomedImage = zoomPanel.querySelector(".zoom-container .zoomed");
if (!zoomedImage) return;
const rect = image.getBoundingClientRect();
let xPercent = Math.min(Math.max(((e.clientX - rect.left) / rect.width) * 100, 0), 100);
let yPercent = Math.min(Math.max(((e.clientY - rect.top) / rect.height) * 100, 0), 100);
let cursorX = e.clientX - rect.left;
let cursorY = e.clientY - rect.top;
cursorBox.style.left = \`\${cursorX - 50}px\`;
cursorBox.style.top = \`\${cursorY - 50}px\`;
cursorBox.style.display = "block";
zoomedImage.style.transformOrigin = \`\${xPercent}% \${yPercent}%\`;
zoomedImage.style.transform = \`translate(-50%, 0%) scale(\${scaleValue})\`;
});
};
image._mouseleaveHandler = () => {
let zoomContainer = zoomPanel.querySelector(".zoom-container");
if (zoomContainer) {
zoomContainer.remove();
}
zoomPanel.style.removeProperty("max-width");
cursorBox.style.display = "none";
};
image.addEventListener("mouseenter", image._mouseenterHandler);
image.addEventListener("mouseleave", image._mouseleaveHandler);
image.addEventListener("mousemove", image._mousemoveHandler);
};
const targetImageSelector = "[class*='ProductRequiredInfoThumbnail_wrapper__'] > :not(.swiper-watch-progress) [class*='ProductImage_image-wrapper'] img";
const initialImageList = document.querySelectorAll(targetImageSelector);
initialImageList.forEach((initialImage) => {
applyZoomEffect(initialImage);
});
const observeMainImage = new MutationObserver(() => {
const updatedImageList = document.querySelectorAll(targetImageSelector);
updatedImageList.forEach((updatedImage) => {
applyZoomEffect(updatedImage);
});
});
observeMainImage.observe(document.body, { childList: true, subtree: true });
})();
`;
document.body.appendChild(script);
})();
</script>
JavaScript
복사
Grid 테마
<script>
(() => {
const script = document.createElement("script");
script.innerHTML = `
(() => {
const applyZoomEffect = (image) => {
if (!image) return;
image.removeEventListener("mouseenter", image._mouseenterHandler);
image.removeEventListener("mouseleave", image._mouseleaveHandler);
image.removeEventListener("mousemove", image._mousemoveHandler);
image.removeEventListener("touchstart", image._touchstartHandler);
image.removeEventListener("touchmove", image._touchmoveHandler);
image.removeEventListener("touchend", image._touchendHandler);
let scaleValue = 2.5; // 이 값은 확대 배율을 조정합니다. 원하는 배율로 변경해 주세요.
let isZoomed = false;
let zoomPanel = document.querySelector("#contentsPanel");
let animationFrameId = null;
let touchStartX = 0;
let touchMoved = false;
if (!zoomPanel) return;
zoomPanel.style.position = "relative";
zoomPanel.style.overflow = "hidden";
let cursorParent = image.closest("[class*='ProductRequiredInfoThumbnail_wrapper__'] > [class*='ProductRequiredInfoThumbnail']:not([class*='ProductRequiredInfoThumbnail_thumb__']) [class*='ProductImage_image-wrapper__']");
if (!cursorParent) return;
let cursorBox = cursorParent.querySelector(".cursor-box");
if (!cursorBox) {
cursorBox = document.createElement("div");
cursorBox.classList.add("cursor-box");
cursorBox.style.position = "absolute";
cursorBox.style.width = "100px";
cursorBox.style.height = "100px";
cursorBox.style.border = "1px solid rgba(255, 255, 255, 0.3)";
cursorBox.style.background = "rgba(255, 255, 255, 0.2)";
cursorBox.style.borderRadius = "50%";
cursorBox.style.pointerEvents = "none";
cursorBox.style.display = "none";
cursorParent.appendChild(cursorBox);
}
if (window.innerWidth <= 768) {
image._touchstartHandler = (e) => {
touchStartX = e.touches[0].clientX;
touchMoved = false;
};
image._touchmoveHandler = (e) => {
let deltaX = Math.abs(e.touches[0].clientX - touchStartX);
if (deltaX > 10) {
touchMoved = true;
}
};
image._touchendHandler = (e) => {
if (touchMoved) return;
e.stopPropagation();
if (isZoomed) {
isZoomed = false;
image.style.transition = "transform 0.2s ease-in-out";
image.style.transform = "scale(1)";
} else {
isZoomed = true;
const rect = image.getBoundingClientRect();
const touchX = ((e.changedTouches[0].clientX - rect.left) / rect.width) * 100;
const touchY = ((e.changedTouches[0].clientY - rect.top) / rect.height) * 100;
image.style.transition = "transform 0.2s ease-out";
image.style.transformOrigin = \`\${touchX}% \${touchY}%\`;
image.style.transform = \`scale(\${scaleValue})\`;
}
};
image.addEventListener("touchstart", image._touchstartHandler);
image.addEventListener("touchmove", image._touchmoveHandler);
image.addEventListener("touchend", image._touchendHandler);
return;
}
image._mouseenterHandler = () => {
let existingZoomedImage = zoomPanel.querySelector(".zoomed");
if (existingZoomedImage) return;
const rect = image.getBoundingClientRect();
const originalWidth = rect.width;
const originalHeight = rect.height;
const panelWidth = zoomPanel.clientWidth;
const panelHeight = zoomPanel.clientHeight;
const widthRatio = panelWidth / originalWidth;
const heightRatio = panelHeight / originalHeight;
const fitScale = Math.min(widthRatio, heightRatio);
let zoomedImage = image.cloneNode(true);
zoomedImage.classList.add("zoomed");
zoomedImage.style.position = "absolute";
zoomedImage.style.width = \`\${originalWidth * fitScale}px\`;
zoomedImage.style.height = \`\${originalHeight * fitScale}px\`;
zoomedImage.style.left = "50%";
zoomedImage.style.top = "50%";
zoomedImage.style.transform = "translate(-50%, -50%) scale(1)";
zoomedImage.style.pointerEvents = "none";
zoomPanel.appendChild(zoomedImage);
cursorBox.style.display = "block";
};
let lastMoveTime = 0;
image._mousemoveHandler = (e) => {
const now = performance.now();
if (now - lastMoveTime < 16) return;
lastMoveTime = now;
if (animationFrameId) {
cancelAnimationFrame(animationFrameId);
}
animationFrameId = requestAnimationFrame(() => {
let zoomedImage = zoomPanel.querySelector(".zoomed");
if (!zoomedImage) return;
const rect = image.getBoundingClientRect();
let xPercent = ((e.clientX - rect.left) / rect.width) * 100;
let yPercent = ((e.clientY - rect.top) / rect.height) * 100;
let cursorX = e.clientX - rect.left;
let cursorY = e.clientY - rect.top;
cursorBox.style.left = \`\${cursorX - 50}px\`;
cursorBox.style.top = \`\${cursorY - 50}px\`;
cursorBox.style.display = "block";
const edgeBuffer = 5;
if (xPercent < edgeBuffer) xPercent = edgeBuffer;
else if (xPercent > 100 - edgeBuffer) xPercent = 100 - edgeBuffer;
if (yPercent < edgeBuffer) yPercent = edgeBuffer;
else if (yPercent > 100 - edgeBuffer) yPercent = 100 - edgeBuffer;
zoomedImage.style.transformOrigin = \`\${xPercent}% \${yPercent}%\`;
zoomedImage.style.transform = \`translate(-50%, -50%) scale(\${scaleValue})\`;
});
};
image._mouseleaveHandler = () => {
let zoomedImage = zoomPanel.querySelector(".zoomed");
if (zoomedImage) {
zoomedImage.remove();
}
cursorBox.style.display = "none";
};
image.addEventListener("mouseenter", image._mouseenterHandler);
image.addEventListener("mouseleave", image._mouseleaveHandler);
image.addEventListener("mousemove", image._mousemoveHandler);
};
const targetImageSelector = "[class*='ProductRequiredInfo_image-panel__'] img:not([class*='ProductRequiredInfoThumbnail_thumb__M5du1'] img)";
const initialImageList = document.querySelectorAll(targetImageSelector);
initialImageList.forEach((initialImage) => {
applyZoomEffect(initialImage);
});
const observeMainImage = new MutationObserver(() => {
const updatedImageList = document.querySelectorAll(targetImageSelector);
updatedImageList.forEach((updatedImage) => {
applyZoomEffect(updatedImage);
});
});
observeMainImage.observe(document.body, { childList: true, subtree: true });
})();
`;
document.body.appendChild(script);
})();
</script>
JavaScript
복사
Round 테마
<script>
(() => {
const script = document.createElement("script");
script.innerHTML = `
(() => {
const applyZoomEffect = (image) => {
if (!image) return;
image.removeEventListener("mouseenter", image._mouseenterHandler);
image.removeEventListener("mouseleave", image._mouseleaveHandler);
image.removeEventListener("mousemove", image._mousemoveHandler);
image.removeEventListener("touchstart", image._touchstartHandler);
image.removeEventListener("touchmove", image._touchmoveHandler);
image.removeEventListener("touchend", image._touchendHandler);
let scaleValue = 2.5;
let isZoomed = false;
let zoomPanel = document.querySelector("[class*='ProductRequiredInfo_wrapper'] > div:nth-child(2)");
let animationFrameId = null;
let touchStartX = 0;
let touchMoved = false;
let originalHeight = zoomPanel.style.height;
if (!zoomPanel) return;
zoomPanel.style.position = "relative";
zoomPanel.style.overflow = "hidden";
let cursorParent = image.closest("[class*='ProductImage_swiper-item-wrapper__'] [class*='Image_wrapper__']");
if (!cursorParent) return;
let cursorBox = cursorParent.querySelector(".cursor-box");
if (!cursorBox) {
cursorBox = document.createElement("div");
cursorBox.classList.add("cursor-box");
cursorBox.style.position = "absolute";
cursorBox.style.width = "100px";
cursorBox.style.height = "100px";
cursorBox.style.border = "1px solid rgba(255, 255, 255, 0.3)";
cursorBox.style.background = "rgba(255, 255, 255, 0.2)";
cursorBox.style.borderRadius = "50%";
cursorBox.style.pointerEvents = "none";
cursorBox.style.display = "none";
cursorParent.appendChild(cursorBox);
}
if (window.innerWidth <= 768) {
image._touchstartHandler = (e) => {
touchStartX = e.touches[0].clientX;
touchMoved = false;
};
image._touchmoveHandler = (e) => {
let deltaX = Math.abs(e.touches[0].clientX - touchStartX);
if (deltaX > 10) {
touchMoved = true;
}
};
image._touchendHandler = (e) => {
if (touchMoved) return;
e.stopPropagation();
if (isZoomed) {
isZoomed = false;
image.style.transition = "transform 0.2s ease-in-out";
image.style.transform = "scale(1)";
} else {
isZoomed = true;
const rect = image.getBoundingClientRect();
const touchX = ((e.changedTouches[0].clientX - rect.left) / rect.width) * 100;
const touchY = ((e.changedTouches[0].clientY - rect.top) / rect.height) * 100;
image.style.transition = "transform 0.2s ease-out";
image.style.transformOrigin = \`\${touchX}% \${touchY}%\`;
image.style.transform = \`scale(\${scaleValue})\`;
}
};
image.addEventListener("touchstart", image._touchstartHandler);
image.addEventListener("touchmove", image._touchmoveHandler);
image.addEventListener("touchend", image._touchendHandler);
return;
}
image._mouseenterHandler = () => {
let existingZoomContainer = zoomPanel.querySelector(".zoom-container");
if (existingZoomContainer) return;
zoomPanel.style.maxWidth = "calc(100% - 50px)";
zoomPanel.style.height = "auto";
const rect = image.getBoundingClientRect();
const aspectRatio = rect.width / rect.height;
let zoomContainer = document.createElement("div");
zoomContainer.classList.add("zoom-container");
zoomContainer.style.position = "absolute";
zoomContainer.style.width = "100%";
zoomContainer.style.height = "auto";
zoomContainer.style.aspectRatio = \`\${aspectRatio}\`;
zoomContainer.style.left = "50%";
zoomContainer.style.top = "0";
zoomContainer.style.transform = "translate(-50%, 0%)";
zoomContainer.style.overflow = "hidden";
zoomContainer.style.pointerEvents = "none";
zoomContainer.style.borderRadius = "20px";
let zoomedImage = image.cloneNode(true);
zoomedImage.classList.add("zoomed");
zoomedImage.style.position = "absolute";
zoomedImage.style.width = "100%";
zoomedImage.style.height = "100%";
zoomedImage.style.left = "50%";
zoomedImage.style.top = "0";
zoomedImage.style.transform = "translate(-50%, 0%) scale(1)";
zoomContainer.appendChild(zoomedImage);
zoomPanel.appendChild(zoomContainer);
cursorBox.style.display = "block";
};
let lastMoveTime = 0;
image._mousemoveHandler = (e) => {
const now = performance.now();
if (now - lastMoveTime < 16) return;
lastMoveTime = now;
if (animationFrameId) {
cancelAnimationFrame(animationFrameId);
}
animationFrameId = requestAnimationFrame(() => {
let zoomedImage = zoomPanel.querySelector(".zoom-container .zoomed");
if (!zoomedImage) return;
const rect = image.getBoundingClientRect();
let xPercent = Math.min(Math.max(((e.clientX - rect.left) / rect.width) * 100, 0), 100);
let yPercent = Math.min(Math.max(((e.clientY - rect.top) / rect.height) * 100, 0), 100);
let cursorX = e.clientX - rect.left;
let cursorY = e.clientY - rect.top;
cursorBox.style.left = \`\${cursorX - 50}px\`;
cursorBox.style.top = \`\${cursorY - 50}px\`;
cursorBox.style.display = "block";
zoomedImage.style.transformOrigin = \`\${xPercent}% \${yPercent}%\`;
zoomedImage.style.transform = \`translate(-50%, 0%) scale(\${scaleValue})\`;
});
};
image._mouseleaveHandler = () => {
let zoomContainer = zoomPanel.querySelector(".zoom-container");
if (zoomContainer) {
zoomContainer.remove();
}
zoomPanel.style.removeProperty("max-width");
zoomPanel.style.height = "fit-content";
cursorBox.style.display = "none";
};
image.addEventListener("mouseenter", image._mouseenterHandler);
image.addEventListener("mouseleave", image._mouseleaveHandler);
image.addEventListener("mousemove", image._mousemoveHandler);
};
const targetImageSelector = "[class*='ProductImage_swiper-item-wrapper__'] img";
const initialImageList = document.querySelectorAll(targetImageSelector);
initialImageList.forEach((initialImage) => {
applyZoomEffect(initialImage);
});
const observeMainImage = new MutationObserver(() => {
const updatedImageList = document.querySelectorAll(targetImageSelector);
updatedImageList.forEach((updatedImage) => {
applyZoomEffect(updatedImage);
});
});
observeMainImage.observe(document.body, { childList: true, subtree: true });
})();
`;
document.body.appendChild(script);
})();
</script>
JavaScript
복사

