本文详细解析如何使用JavaScript实现类似电商平台的商品放大镜效果。通过HTML构建小图、大图与遮罩层结构,CSS控制样式与隐藏逻辑,JS处理鼠标移入移出及移动事件。核心在于利用动态等比缩放算法,确保遮罩层移动距离与大图显示区域比例一致,从而提供流畅的局部放大浏览体验。
本文将演示如何实现一个类似淘宝、京东等电商平台商品详情页的放大镜浏览功能。
最终实现的交互效果如下图所示。

功能分析与准备工作
要实现这一效果,需完成以下基础工作: 1. 结构准备:创建三个核心DOM元素,分别对应显示缩略图的小容器、用于展示放大细节的大容器以及跟随鼠标移动的半透明遮罩层。 2. 交互逻辑: - 获取鼠标在容器内的坐标位置,并实时计算遮罩层的位置。 - 进行边界检测:当遮罩层移动至小容器边缘时,限制其继续移动,防止超出范围。 - 计算比例关系:根据遮罩层移动距离,按比例同步移动大容器内的图片。 - 关键步骤:在页面加载完成后,计算小容器与遮罩层的尺寸比例,并据此动态调整大容器内图片的尺寸,确保放大倍数恒定且图像清晰。
实现步骤详解
首先,准备两张分辨率不同的同一商品图片,并搭建基础的HTML结构以引入图片资源。
<body>
<div id="div-small">
<img src="./imgs/小1.jpg" id="img-small">
<div id="div-mask"></div>
</div>
<div id="div-big">
<img src="./imgs/大2.jpg" id="img-big">
</div>
</body>
结构搭建完成后,页面尚无交互效果,因此需要编写CSS样式来定义各元素的布局、尺寸及初始状态。
<style>
img {
vertical-align: top;
}
/*小盒子*/
#div-small {
width: 350px;
height: 350px;
outline: 2px solid black;
position: absolute;
top: 50px;
left: 0;
/*鼠标变成小手样式*/
cursor: pointer;
}
/*大盒子*/
#div-big {
width: 500px;
height: 500px;
outline: 2px solid black;
position: absolute;
left: 350px;
top: 50px;
overflow: hidden;
display: none;
}
/*遮罩层*/
#div-mask {
width: 150px;
height: 150px;
background-color: aqua;
opacity: 0.5;
position: absolute;
top: 0;
left: 0;
/*对鼠标事件失去作用*/
pointer-events: none;
display: none;
}
</style>
为了直观展示布局效果,在隐藏遮罩层和大容器之前,先截取当前页面状态如图;实际开发中,这两个元素在初始状态下应设置为隐藏。

完成基础样式后,引入JavaScript逻辑以实现交互。主要逻辑包括:当鼠标移入小容器时,显示遮罩层和大容器;当鼠标移出小容器时,隐藏这两个元素。
//鼠标移入事件
div_small.onmouseover = function () {
//鼠标移入小盒子时,遮罩层和大盒子显示
div_mask.style["display"] = "block";
div_big.style["display"] = "block";
}
//鼠标移出事件
div_small.onmouseout = function () {
//鼠标移出小盒子时,遮罩层和大盒子消失
div_mask.style["display"] = "none";
div_big.style["display"] = "none";
//同时让大盒子图片回到原位
img_big.style["margin-left"] = 0;
img_big.style["margin-top"] = 0;
}
在实现移入移出事件的基础上,进一步处理鼠标在小容器内移动时的逻辑:左侧遮罩层随鼠标移动,右侧大容器内的图片根据遮罩层的位移进行对应的放大显示。
//(小盒子内)鼠标移动事件
div_small.onmousemove = function (e) {
//通过1和2可以确保鼠标在遮罩层的正中间
//1.获取鼠标在小盒子的位置x0,y0
let x0 = e.offsetX;
let y0 = e.offsetY;
//2.计算当前位置(左上角)
let cur_x = x0 - div_mask.offsetWidth / 2;
let cur_y = y0 - div_mask.offsetHeight / 2;
//2-1.防止遮罩越界(超出盒子区域),超出则拉回
cur_x = cur_x < 0 ? 0 : cur_x;
cur_x = cur_x > div_small.offsetWidth - div_mask.offsetWidth ? div_small.offsetWidth - div_mask.offsetWidth : cur_x;
cur_y = cur_y < 0 ? 0 : cur_y;
cur_y = cur_y > div_small.offsetHeight - div_mask.offsetHeight ? div_small.offsetHeight - div_mask.offsetHeight : cur_y;
//3.设置遮罩的(左上角)位置
div_mask.style["left"] = cur_x + "px";
div_mask.style["top"] = cur_y + "px";
//4.让大图挪动(大图移动距离等于小图距离左边的宽高乘以大小图的宽高比)
img_big.style["margin-left"] = -cur_x * img_big.offsetWidth / img_small.offsetWidth + "px";
img_big.style["margin-top"] = -cur_y * img_big.offsetHeight / img_small.offsetHeight + "px";
}
初步实现后,发现右侧大图移动距离与左侧遮罩层移动距离的比例存在细微误差,导致放大效果不够精准。
为解决上述比例不一致的问题,需执行关键处理步骤:通过动态计算并设置大图片的宽高,使左右两侧的尺寸比例保持严格一致,从而优化放大镜的视觉效果。
//图片会在页面内容加载完毕后才会开始加载,所以使用window.onload.
window.onload = function () {
//计算小图片/遮罩层的比例=大图片/大盒子的比例===>即动态设置大图片的宽高,让大图片始终贴合边框(注意:元素设置display:none后,offsetWidth这种获取宽高将会失效)
img_big.style.width = (img_small.offsetWidth / parseFloat((window.getComputedStyle(div_mask)["width"])) * parseFloat((window.getComputedStyle(div_big)["width"]))) + "px";
img_big.style.height = (img_small.offsetHeight / parseFloat((window.getComputedStyle(div_mask)["height"])) * parseFloat((window.getComputedStyle(div_big)["height"]))) + "px";
}
以上即为实现放大镜功能的全部逻辑思路,希望对读者有所帮助。
完整代码示例
<!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>
img {
vertical-align: top;
}
/*小盒子*/
#div-small {
width: 350px;
height: 350px;
outline: 2px solid black;
position: absolute;
top: 50px;
left: 0;
/*鼠标变成小手样式*/
cursor: pointer;
}
/*大盒子*/
#div-big {
width: 500px;
height: 500px;
outline: 2px solid black;
position: absolute;
left: 350px;
top: 50px;
overflow: hidden;
display: none;
}
/*遮罩层*/
#div-mask {
width: 150px;
height: 150px;
background-color: aqua;
opacity: 0.5;
position: absolute;
top: 0;
left: 0;
/*对鼠标事件失去作用*/
pointer-events: none;
display: none;
}
</style>
</head>
<body>
<div id="div-small">
<img src="./imgs/小1.jpg" id="img-small">
<div id="div-mask"></div>
</div>
<div id="div-big">
<img src="./imgs/大2.jpg" id="img-big">
</div>
</body>
<script>
//获取标签
let div_small = document.querySelector("#div-small");
let div_big = document.querySelector("#div-big");
let div_mask = document.querySelector("#div-mask");
let img_small = document.querySelector("#img-small");
let img_big = document.querySelector("#img-big");
//假定鼠标控制遮罩层在当前盒子的正中间,我们需要先求出遮罩层左上角的坐标(x=e.offsetX-mask.offsetWidth,y=e.offsetY-mask.offsetHeight)
//鼠标移入事件
div_small.onmouseover = function () {
//鼠标移入小盒子时,遮罩层和大盒子显示
div_mask.style["display"] = "block";
div_big.style["display"] = "block";
}
//鼠标移出事件
div_small.onmouseout = function () {
//鼠标移出小盒子时,遮罩层和大盒子消失
div_mask.style["display"] = "none";
div_big.style["display"] = "none";
//同时让大盒子图片回到原位
img_big.style["margin-left"] = 0;
img_big.style["margin-top"] = 0;
}
//(小盒子内)鼠标移动事件
div_small.onmousemove = function (e) {
//通过1和2可以确保鼠标在遮罩层的正中间
//1.获取鼠标在小盒子的位置x0,y0
let x0 = e.offsetX;
let y0 = e.offsetY;
//2.计算当前位置(左上角)
let cur_x = x0 - div_mask.offsetWidth / 2;
let cur_y = y0 - div_mask.offsetHeight / 2;
//2-1.防止遮罩越界(超出盒子区域),超出则拉回
cur_x = cur_x < 0 ? 0 : cur_x;
cur_x = cur_x > div_small.offsetWidth - div_mask.offsetWidth ? div_small.offsetWidth - div_mask.offsetWidth : cur_x;
cur_y = cur_y < 0 ? 0 : cur_y;
cur_y = cur_y > div_small.offsetHeight - div_mask.offsetHeight ? div_small.offsetHeight - div_mask.offsetHeight : cur_y;
//3.设置遮罩的(左上角)位置
div_mask.style["left"] = cur_x + "px";
div_mask.style["top"] = cur_y + "px";
//4.让大图挪动(大图移动距离等于小图距离左边的宽高乘以大小图的宽高比)
img_big.style["margin-left"] = -cur_x * img_big.offsetWidth / img_small.offsetWidth + "px";
img_big.style["margin-top"] = -cur_y * img_big.offsetHeight / img_small.offsetHeight + "px";
}
//图片会在js加载完毕后才会开始加载,所以使用window.onload.
window.onload = function () {
//计算小图片/遮罩层的比例=大图片/大盒子的比例===>即动态设置大图片的宽高,让大图片始终贴合边框(注意:元素设置display:none后,offsetWidth这种获取宽高将会失效)
img_big.style.width = (img_small.offsetWidth / parseFloat((window.getComputedStyle(div_mask)["width"])) * parseFloat((window.getComputedStyle(div_big)["width"]))) + "px";
img_big.style.height = (img_small.offsetHeight / parseFloat((window.getComputedStyle(div_mask)["height"])) * parseFloat((window.getComputedStyle(div_big)["height"]))) + "px";
}
</script>
</html>总结
本文介绍了基于JavaScript实现商品放大镜效果的完整流程。如需了解更多前端交互技巧,可查阅本站相关文章或继续关注后续更新,感谢支持。