# 兩種 JS放大鏡效果(Magnifier effect) ### **撰寫程式:HTML | CSS | JS** ### 相關連結:[**Codepen**](https://codepen.io/liu_0821/pen/qBQYdYQ)、[**Medium**](https://medium.com/@LindaLiu0821/javascript%E5%85%A9%E7%A8%AE%E6%94%BE%E5%A4%A7%E9%8F%A1%E6%95%88%E6%9E%9C-magnifier-effect-fa5b98a4f212) ![FotoJet](https://hackmd.io/_uploads/SkJfqIGdT.jpg) ## HTML 擷取片段 > ###### 第一種 - 主要是兩張圖片經過JS計算對比。 ``` <div class="box"> <div class ="ImgBox"> <img src="https://cdn1.techbang.com/system/images/329622/original/db6f84129f8c8e06d93c0abb36c74247.png?1450808173" alt=""> <div class="glass"></div> </div> <div class="showBox"> <img src="https://cdn1.techbang.com/system/images/329622/original/db6f84129f8c8e06d93c0abb36c74247.png?1450808173" alt=""> </div> </div> ``` > ###### 第二種 - 透過JS設定`backgroundImage`對比圖片。 ``` <div class="box"> <div class="zoom-wrap"> <img class="target" src="https://cdn1.techbang.com/system/images/329622/original/db6f84129f8c8e06d93c0abb36c74247.png?1450808173"> <div class="zoom-area"></div> </div> </div> ``` ## CSS 擷取片段 > ###### 第一種方式需要注意倍數問題,標籤必須設定長寬;除此之外,大致上比較著需要注意的是`position`的使用。 ``` // 第一種 .ImgBox{ line-height: 0; width: 360px; /*一定要設定高寬*/ height: 100%; position: relative; display: flex; justify-content: center; background-color: #fff; } .ImgBox >img{ display: block; width: 100%; object-fit:contain; } .glass{ //灰色區塊 position: absolute; top: 0; left: 0; width: 180px; /*一定要設定高寬*/ height: 180px; opacity: .45; background-color: #000; border: 1px solid #333; display: none; } .showBox{ // 顯示放大的div position: relative; left: 15px; width: 360px; /*一定要設定高寬*/ height: 360px; background-color: #fff; overflow: hidden; display: none; } .showBox > img{ position: absolute; /* width: 1080px; height: auto;*/ } ``` ``` // 第二種 .zoom-wrap{ position: relative; display: inline-block; width: 40%; } .target{ position: relative; width: 100%; } .zoom-area{ // 放大鏡 position: absolute; left: 0px; top: 0px; display: block; width: 200px; height: 200px; border-radius: 100%; box-shadow: 0 0 5px rgba(255,255,255,.3), inset 0 0 5px rgba(0,0,0,.3); background-repeat: no-repeat; pointer-events: none; transition: .3s ease-out; } .zoom-area::before { // 灰灰滑鼠區塊 content: ' '; display: block; position: relative; top: -40px; left: -40px; width: 80px; height: 80px; border-radius: 100%; background-color: #2f2f2f54; } ``` ## JS > ###### 第一種放大鏡效果 ``` function runGlass1(){ /*----- 第一種 -----*/ let ImgBox = document.querySelector('.ImgBox'); let glass = document.querySelector('.glass'); // 滑鼠移動灰色區塊 let showBox = document.querySelector('.showBox'); // 顯示放大區塊 let bigImage = document.querySelector('.showBox > img'); // 放大區塊的圖 let originallyImage = document.querySelector('.ImgBox > img'); // 被放大區塊的圖 // 移入顯示 ImgBox.addEventListener('mouseover', () => { glass.style.display = 'block'; showBox.style.display = 'block'; }); // 移出隱藏 ImgBox.addEventListener('mouseout', () => { glass.style.display = 'none'; showBox.style.display = 'none'; }); // 移動時放大取位置 ImgBox.addEventListener('mousemove', (e) => { // pageX / pageY -> ducoment的水平/垂直座標 // offsetLeft / offsetTop -> 滑鼠對於該區塊的水平/垂直偏移量 let x = e.pageX - ImgBox.offsetLeft; let y = e.pageY - ImgBox.offsetTop; // offsetWidth / offsetHeight -> 是「元素本身」的寬度/高度,並完整了包含了邊界、捲軸及padding // 在這裡 x 減去 glass一半的寬度可以得到 glass 對于的 ImgBox 的偏移量 == 絕對定位的left let width = x - glass.offsetWidth / 2; let height = y - glass.offsetHeight / 2; // 讓放大鏡(glass)不超過原圖的大小(內部) if (width <= 0){ width = 0; } else if (width >= ImgBox.offsetWidth - glass.offsetWidth){ width = ImgBox.offsetWidth - glass.offsetWidth; } if (height <= 0){ height = 0; } else if (height >= ImgBox.offsetHeight - glass.offsetHeight ){ height = ImgBox.offsetHeight - glass.offsetHeight; } // 放大鏡位置(更新) glass.style.left = width + 'px'; glass.style.top = height + 'px'; // 圖片寬度 -> 原圖寬度 × 顯示元素寬度 ÷ 放大鏡寬度 bigImage.style.width = originallyImage.offsetWidth * showBox.offsetWidth / glass.offsetWidth+ "px"; // 移動距離 -> -絕對定位 × 放大圖寬度 ÷ 原圖寬度 bigImage.style.left = - width * bigImage.offsetWidth / originallyImage.offsetWidth + "px"; bigImage.style.top = - height * bigImage.offsetHeight / originallyImage.offsetHeight +"px"; }); } ``` > ###### 第二種放大鏡效果 ``` function runGlass2(){ let scale = 2; //放大倍数 let showZoomArea = false; // 判斷要不要顯示放大鏡 // 移除滑動圖片 let target = document.getElementById('image'); target.addEventListener('mousemove', zoomImgMouseMove, false); target.addEventListener('mouseenter', zoomImgMouseEnter, false); target.addEventListener('mouseleave', zoomImgMouseleave, false); // 放大顯示區域 let zoomArea = document.getElementById('showBox'); // 設置放大背景圖 zoomArea.style.backgroundImage = 'url('+target.getAttribute('src')+')'; // 圖片加載至背景 // getBoundingClientRect() -> 取得元素 element 「相對於視窗」的座標 let targetRect = target.getBoundingClientRect(); let targetWidth = targetRect.width; let targetHeight = targetRect.height; // 背景圖片尺寸大小 () zoomArea.style.backgroundSize = (targetWidth * scale)+'px '+(targetHeight * scale)+'px'; let zoomRect = zoomArea.getBoundingClientRect(); let widthHalf = zoomRect.width / 2; let heightHalf = zoomRect.height / 2; let offsetX = 0; let offsetY = 0; function zoomImgMouseMove(e){ offsetX = e.offsetX; offsetY = e.offsetY; } function zoomImgMouseEnter(){ showZoomArea = true; } function zoomImgMouseleave(){ showZoomArea = false; } setInterval(function(){ zoomArea.style.backgroundPosition = -(offsetX * scale - widthHalf)+'px '+(-(offsetY * scale - heightHalf))+'px'; // 放大鏡居中 zoomArea.style.left = (offsetX - widthHalf) + 'px'; zoomArea.style.top = (offsetY - heightHalf) + 'px'; // 放大镜在右下角 if((offsetX + zoomRect.width) > window.innerWidth){ zoomArea.style.left = (offsetX - zoomRect.width) + 'px'; }else{ zoomArea.style.left = offsetX + 'px'; } if((offsetY + zoomRect.height) > window.innerHeight){ zoomArea.style.top = (offsetY - zoomRect.height) + 'px'; }else{ zoomArea.style.top = offsetY + 'px'; } setZoomArea(); }, 100) function setZoomArea(){ if(showZoomArea) zoomArea.style.transform = 'scale(1)'; // 放大一倍 else zoomArea.style.transform = 'scale(0)'; //會消失 } setZoomArea(); } ``` --- ##### ヽ(∀゚ )人(゚∀)人( ゚∀)人(∀゚ )人(゚∀)人( ゚∀)ノヽ(∀゚ )人(゚∀゚)人( ゚∀)人(∀゚ )人(゚∀゚)人( ゚∀)人(∀゚ )人( ゚∀)人 ##### 以上 如果註解哪裡有錯誤或有問題,歡迎提出來一起討論~~~~