# 兩種 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)

## 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();
}
```
---
##### ヽ(∀゚ )人(゚∀)人( ゚∀)人(∀゚ )人(゚∀)人( ゚∀)ノヽ(∀゚ )人(゚∀゚)人( ゚∀)人(∀゚ )人(゚∀゚)人( ゚∀)人(∀゚ )人( ゚∀)人
##### 以上 如果註解哪裡有錯誤或有問題,歡迎提出來一起討論~~~~