我们经常在淘宝类似的网站可以看到一个图片放大镜的功能,鼠标移动到一张商品图片上会有一个小遮罩,同时这个被遮罩的部分会在旁边放大显示,本文粗略地实现一下这个功能,作为JS的入门练习

最终效果见如下链接

CSS部分

首先我们设置一个常规的图片css

1
2
3
4
5
6
7
8
9
10
.img {
width: 300px;
height: 450px;
background-image: url(./img.png);
background-size: 300px 450px;
background-position: center center;
background-repeat: no-repeat;
display: inline-block;
position: relative;
}

考虑到一会儿需要有一个遮罩小块在这张图片上相对滑动,所以先将position属性设置为relative

预想放大后的图片是和原图并在同一排,将display调整为行内块

然后我们将小块放上去,设置一个橙色的小方块,根据海绵宝宝脸部大小设置合适的长宽,设置定位属性为absolute以相对img定位,因为我们希望的是当鼠标移入图片的时候有个小方块遮罩跟随,因此先将小方块的display设置成none,当鼠标移入的时候再将其调整为block

1
2
3
4
5
6
7
.mask {
width: 80px;
height: 90px;
background-color: rgba(255, 157, 0, 0.603);
display: none;
position: absolute;
}

最后,设置放大后图片的位置和属性,同样先设置为display: none

1
2
3
4
5
6
7
8
9
10
.big {
border: 5px solid orange;
width: 160px;
height: 180px;
background-image: url(./img.png);
background-size: 600px 900px;
background-position: 0 0;
background-repeat: no-repeat;
display: none;
}

将显示的部分长宽设置为遮罩块的两倍,同时图片的大小也需要是原来图片的两倍

JS部分

首先获取图片,遮罩,放大显示框的dom元素

1
2
3
var img = document.querySelector('.img')
var mask = document.querySelector('.mask')
var big = document.querySelector('.big')

对于遮罩块和放大区域的出现和消失只要监听鼠标移入图片区域和移出的事件即可

1
2
3
4
5
6
7
8
img.addEventListener('mouseover', function () {
mask.style.display = "block"
big.style.display = "inline-block"
})
img.addEventListener('mouseout', function () {
mask.style.display = "none"
big.style.display = "none"
})

然后我们监听鼠标的移动并根据鼠标位置调整遮罩块的位置以及放大区域的内容

具体的算法思路是

  1. 获取鼠标的位置 (evt.pageX, evt.pageY)
  2. 计算遮罩的左上角位置 (利用遮罩的长宽)
  3. 计算放大区域图片背景的移动位置 (利用放大区域背景和原图的大小关系)

具体代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
img.addEventListener('mousemove', function (evt) {
// 计算鼠标在盒子内的坐标
let x = evt.pageX - this.offsetLeft
let y = evt.pageY - this.offsetTop
// 计算遮罩的左上角坐标值
let maskX = x - mask.offsetWidth / 2
let maskY = y - mask.offsetHeight / 2
var widthMax = img.offsetWidth - mask.offsetWidth
var heightMax = img.offsetHeight - mask.offsetHeight
// 边界处理
maskX = Math.min(Math.max(0,maskX),widthMax)
maskY = Math.min(Math.max(0,maskY),heightMax)
mask.style.left = maskX + 'px'
mask.style.top = maskY + 'px'
// 放大区域图片背景的左上角位置计算
big.style.backgroundPosition= -maskX*2 + "px" + " " + -maskY*2 +"px"
})

evt.pageX和evt.pageY可以获取鼠标在页面中的位置

offset参数是用于获取dom对象的偏移值的,如果父级元素(祖先元素)有定位属性,则offsetTopoffsetLeft是相对于父级元素的偏移,否则是相对于body元素的偏移,offsetWidthoffsetHeight则可以得到盒子的宽度和高度(包含padding,边框和内容)

利用这些信息,我们可以计算出鼠标相对于图片左上角的偏移,也就是我们需要的遮罩块的中心点的偏移,因为遮罩块的位置计算需要左上角坐标,因此还需要减去遮罩块长宽的一半

做完这一些,我们发现当遮罩块移动的时候可能会超出图片,因此我们还需要做一个边界处理,计算一下遮罩块最多可以移动的位置,做一个极大极小处理,这样子可以保证遮罩块在图片内,不会超出

而放大区域的处理就比较简单了,因为设置了放大区域的背景图片长宽是原图的两倍,所以遮罩块移动的距离就是放大区域背景图片移动距离的$\frac{1}{2}$,我们设置其两倍移动距离即可 (即左上角位置是-2*(x,y))

海绵宝宝放大镜完成