JavaScript实现仿京东商品放大镜效果教程
本文详解如何使用JavaScript实现仿京东的商品放大镜功能。核心逻辑包括:鼠标移入显示黄色遮挡层与大图,移出隐藏;通过监听小图盒子的mousemove事件获取鼠标坐标,计算遮挡层相对于父容器的left和top值;同时处理边界限制,确保遮挡层不超出小图范围,并同步移动大图实现放大查看效果。
功能实现概述
功能实现
鼠标交互与显隐控制
第一步:实现鼠标交互的显隐逻辑。当鼠标进入小图片盒子区域时,黄色遮挡层和大图片容器需要显示出来;当鼠标离开该区域时,这两个元素则隐藏。
遮挡层跟随鼠标移动逻辑
第二步:实现黄色遮挡层跟随鼠标移动的效果。
核心思路是将鼠标的实时坐标赋值给遮挡层,使其位置随鼠标移动而不断更新。
需要注意的是,不能直接将鼠标的绝对坐标赋给遮挡层,因为遮挡层的位置是相对于其父盒子(小图片盒子)进行定位的。
因此,首先需要计算鼠标在小图片盒子内部的相对坐标。
获取到相对坐标后,将其分别赋值给遮挡层的left和top属性,从而控制遮挡层的位置。
这里需要绑定鼠标移动事件(mousemove),且该事件监听器应挂载在小图片盒子上,确保鼠标仅在盒子内部移动时触发。
在初步实现后发现遮挡层位置偏移,这是因为直接赋值未考虑遮挡层自身的尺寸。正确的做法是,从鼠标坐标中减去遮挡层自身高度和宽度的一半,以鼠标中心点对准遮挡层中心。
必须限制遮挡层的移动范围,确保其始终位于小图片盒子内部,不会溢出。
当计算出的left或top值小于0时,将其强制设置为0,防止遮挡层移出左上边界。
当计算出的left或top值大于遮挡层允许的最大移动距离时,将其设置为该最大值,防止移出右下边界。
遮挡层的最大移动距离计算公式为:小图片盒子的宽度减去遮挡层盒子的宽度(高度同理)。
大图片联动移动处理
第三步:实现大图片的联动移动。当黄色遮挡层在小图片上移动时,大图片需要在其容器中进行反向或比例移动,以展示对应的放大区域。



这一部分的逻辑实现相对复杂,涉及坐标换算与边界处理的细节。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
width: 300px;
height: 300px;
position: relative;
border: 1px solid #ccc;
}
.tupian {
width: 100%;
height: 100%;
}
/* 不能是box里面所有地img百分百比例,这样是无法再大盒子里面移动图片地 */
.mask {
display: none;
width: 150px;
height: 150px;
background: rgba(228, 248, 138, 0.3);
position: absolute;
top: 0px;
left: 0px;
cursor: move;
}
.big {
display: none;
width: 400px;
height: 400px;
position: absolute;
top: 0px;
left: 310px;
background-color: pink;
overflow: hidden;
}
.big img {
position: absolute;
top: 0px;
left: 400px
}
</style>
</head>
<body>
<div class="box"><img src="http://img14.360buyimg.com/n1/s450x450_jfs/t1/131049/21/21277/105207/61dfcd46E2318f45d/32bd21d7732845bc.jpg" alt="" class="tupian">
<div class="mask"></div>
<div class="big"><img src="http://img14.360buyimg.com/n1/s450x450_jfs/t1/131049/21/21277/105207/61dfcd46E2318f45d/32bd21d7732845bc.jpg" alt="" class="bigimg"></div>
</div>
<script>
//当鼠标放在box上,箭头变为移动
var tupian = document.querySelector('.tupian')
var mask = document.querySelector('.mask')
var big = document.querySelector('.big')
var box = document.querySelector('.box')
var bigimg = document.querySelector('.bigimg')
//鼠标放在小图片上时,黄色遮挡层显示以及大盒子显示
box.addEventListener('mouseover', function() { //不能是图片添加的事件,因为mask一显示就会把图片给挡住
mask.style.display = 'block'
big.style.display = 'block'
})
//鼠标离开小图片,就隐藏
box.addEventListener('mouseout', function() {
mask.style.display = 'none'
big.style.display = 'none'
})
box.addEventListener('mousemove', function(e) {
//先计算出鼠标在盒子内地坐标
var x = e.pageX - box.offsetLeft
var y = e.pageY - box.offsetTop
//减75(盒子地一般)是为了让鼠标位于盒子地中心
//mask移动地距离
var maskx = x - mask.offsetWidth / 2
var masky = y - mask.offsetHeight / 2 //最好这样赋值一下,就不用考虑if里面地单位情况
//约束--设置小盒子移动范围
if (maskx <= 0) {
maskx = 0
} else if (maskx >= box.offsetWidth - mask.offsetWidth) {
maskx = box.offsetWidth - mask.offsetWidth
}
if (masky <= 0) {
masky = 0
} else if (masky >= box.offsetHeight - mask.offsetHeight) {
masky = box.offsetHeight - mask.offsetHeight
}
mask.style.left = maskx + 'px'
mask.style.top = masky + 'px'
var maxMax = box.offsetWidth - mask.offsetWidth //遮挡层地最大移动距离
var bigMax = bigimg.offsetWidth - big.offsetWidth //大图片地最大移动距离
//大图片地移动距离
var bigx = maskx * bigMax / maxMax
var bigy = masky * bigMax / maxMax
bigimg.style.left = -bigx + 'px'
bigimg.style.top = -bigy + 'px'
})
// tupian.addEventListener('mouseover', function() {
// tupian.addEventListener('mousemove', function(e1) {
// mask.style.display = 'block'
// var x = e1.pageX - tupian.offsetLeft
// var y = e1.pageY - tupian.offsetTop
// mask.style.left = x - 75 + 'px'
// mask.style.top = y - 75 + 'px'
// if (mask.style.bottom < -10) {
// mask.style.bottom = 0 + 'px'
// }
// })
//让遮罩层跟随鼠标移动
// div.addEventListener('mousemove', function(e) {
// var a = e.pageX - div.offsetLeft
// var b = e.pageY - div.offsetTop
// if (a > 75) {
// mask.style.left = e.pageX - div.offsetLeft - x + 'px'
// }
// if (mask.style.left < 0) {
// mask.style.left = 0
// }
// if (b > 75) {
// mask.style.top = e.pageY - y + 'px'
// }
// if (mask.style.top < 0) {
// mask.style.top = 0
// }
// mask.style.left = x - 75 + 'px' //鼠标并不一定要在mask的正中间
// mask.style.top = y - 75 + 'px'
// div.addEventListener('mousemove', fn)
// function fn(e) { //这个函数一定要写在mousedown函数里面才能取出x和y
// //不能让白色遮罩层出box盒子
// mask.style.left = e.pageX - x - 75 + 'px'
// mask.style.top = e.pageY - y - 75 + 'px'
// }
// })
//鼠标离开盒子就取消移动事件
// div.addEventListener('mouseout', function() {
// div.removeEventListener('mousemove', fn)
// })
// })
</script>
</body>
</html>
复盘总结

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
width: 300px;
height: 300px;
position: relative;
}
.pre {
width: 100%
}
.mask {
display: none;
position: absolute;
top: 0px;
left: 0px;
width: 100px;
height: 150px;
background-color: pink;
opacity: 0.3;
}
.big {
/* display: none; */
position: absolute;
top: 0px;
left: 310px;
width: 400px;
height: 400px;
background-color: pink;
overflow: hidden;
/* 当大盒子里面地图片出来地时候,就将出来部分地图片进行隐藏 */
}
/* 鼠标进入小盒子地时候,变为移动 */
.bigtu {
position: absolute;
top: 0px;
left: 0px;
}
.box:hover {
cursor: move
}
</style>
</head>
<body>
<div class="box">
<img src="http://img14.360buyimg.com/n1/s450x450_jfs/t1/131049/21/21277/105207/61dfcd46E2318f45d/32bd21d7732845bc.jpg" alt="" class="pre">
<div class="mask"></div>
<div class="big"> <img src="http://img14.360buyimg.com/n1/s450x450_jfs/t1/131049/21/21277/105207/61dfcd46E2318f45d/32bd21d7732845bc.jpg" alt="" class="bigtu"></div>
</div>
<script>
//1、鼠标进入小盒子,遮罩层、大盒子出现
var box = document.querySelector('.box')
var mask = document.querySelector('.mask')
var big = document.querySelector('.big')
var bigtu = document.querySelector('.bigtu')
box.addEventListener('mouseover', function() {
mask.style.display = 'block'
big.style.display = 'block'
})
//2、鼠标离开小盒子地时候,遮罩层、大盒子隐藏
box.addEventListener('mouseout', function() {
mask.style.display = 'none'
big.style.display = 'none'
})
//3、添加移动效果,遮罩层跟随鼠标移动,鼠标再小盒子地坐标就是遮罩层地位置
box.addEventListener('mousemove', function(e) {
//求鼠标在小盒子里面地坐标
var x = e.pageX - box.offsetLeft
var y = e.pageY - box.offsetTop
//将鼠标地坐标给遮罩层
// mask.style.left = x + 'px'
// mask.style.top = y + 'px'
//鼠标应该位于遮罩层地中心位置
var maskx = x - mask.offsetWidth / 2
var masky = y - mask.offsetHeight / 2
//4、应该约束遮罩层地移动范围,也就是约束鼠标地位置,maskx、masky要大于0,以及要小于一个值,不能初到底部下面或者右边地右边
if (maskx < 0) {
maskx = 0
}
if (maskx > box.offsetWidth - mask.offsetWidth) {
maskx = box.offsetWidth - mask.offsetWidth
}
if (masky < 0) {
masky = 0
}
if (masky > box.offsetHeight - mask.offsetHeight) {
masky = box.offsetHeight - mask.offsetHeight
}
mask.style.left = maskx + 'px'
mask.style.top = masky + 'px'
//5、要让大盒子里面地图片移动,加相对定位.原理鼠标在小盒子里面移动地距离与鼠标在大盒子里面移动地距离是成比例地.其实就是小盒子图片地left、top值与大盒子里面地left、top值是成比例地 弄清楚这个比例关系很重要
var bigtux = maskx * (bigtu.offsetWidth - big.offsetWidth) / (box.offsetWidth - mask.offsetWidth)
var bigtuy = masky * (bigtu.offsetHeight - big.offsetHeight) / (box.offsetHeight - mask.offsetHeight)
bigtu.style.left = -bigtux + 'px'
bigtu.style.top = -bigtuy + 'px'
//应该也要对大盒子里面地图片移动范围进行约束
//忽视了一点:bigtu地大小是450*450地,所以大盒子不能直接等于450*450;应该小于450*450;这样图片在大盒子里面才有移动地余地
//相当于左侧地小盒子,对图片进行了缩小,需要在大盒子里面显示原始图片,位置对应
})
</script>
</body>
</html>以上是利用JavaScript实现仿京东放大镜效果的详细步骤与逻辑解析,更多关于JavaScript前端特效的资料,建议关注本站其他相关技术文章。
JS动态构建复杂嵌套JSON对象的方法
2026-11-05 15:41:52
JS负数取余为什么是负数?详解余数与模运算区别
2026-11-05 13:34:41
JS 解压出现乱码或报错怎么解决?
2026-11-05 12:32:38
JS 中 startsWith、indexOf 与正则判断字符串前缀的对比
2026-11-04 22:19:43
JS解析Excel后怎么将数据转换为JSON格式
2026-11-04 20:58:28
