Search

상품 상세 대표 이미지 확대하기

태그
일반
1 more property
아래 HTML 소스 코드를 활용하면 상품 상세 대표 이미지에 마우스를 호버할 때 확대 효과를 적용할 수 있어요.
데스크톱: 커서가 대표 이미지에 호버되었을 때 작동합니다.
모바일: 대표 이미지에 터치하면 터치한 영역이 확대됩니다.
코드 상에서  let scaleValue = 2.5; 의 숫자를 조정하여 배율을 변경할 수 있습니다.
페이지 오른쪽의 목차를 눌러 해당 테마로 바로 이동하면 편리합니다.

상품 상세 대표 이미지 확대하기

디자인 에디터에 접속하고 상품 상세로 이동해 주세요.
상세의 본문 영역에 HTML 섹션을 추가하고 공통에 테마에 해당하는 코드를 넣고, 발행하기 해주세요.

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
복사
HTML 섹션 안내서로 돌아가기