纯JS实现商品详情图放大镜效果:鼠标跟随与坐标计算

作者:白露时间:2026-10-24 12:48:51浏览:171

本文详解如何使用原生JavaScript实现电商常见的商品细节图查看功能。通过监听鼠标经过、离开及移动事件,结合遮罩层与大图的比例缩放算法,计算鼠标坐标并同步更新大图位置。文章涵盖HTML结构搭建、CSS定位样式及JS核心逻辑,重点解析遮罩层移动范围限制与大图反向移动的坐标计算公式,帮助开发者理解底层实现原理。

本文介绍一种电商平台常见的商品细节图查看交互案例,类似于京东手机类目详情页中,用户鼠标悬停在左侧小图上时,右侧同步显示该区域放大后的图片效果。该功能主要依赖JavaScript处理鼠标经过、鼠标离开以及鼠标移动等事件,并涉及一个关键的坐标比例计算公式。首先展示最终实现的效果:

某电商平台的效果演示如下:

以下是实现该功能的具体代码部分:

以下是实现该功能的具体代码部分:

HTML结构部分:


<div class="box">
        <img src="images/s3.png" alt="">
        <div class="mask"></div>
        <div class="big">
            <img src="images/big.jpg" alt="">
        </div>
</div>

CSS样式部分:


<style>
        * {
            padding: 0;
            margin: 0;
        }
 
        .box {
            position: relative;
            top: 70px;
            left: 30px;
            width: 400px;
            height: 400px;
            border: 1px solid #ccc;
        }
        .box > img {
            height: 100%;
        }
 
        .mask {
            display: none;
            position: absolute;
            top: 0;
            left: 0;
            width: 300px;
            height: 300px;
            box-sizing: border-box;
            background-color: rgba(254, 222, 79, .5);
            border: 1px solid #ccc;
            cursor: move;
            /*让鼠标的状态改成十字型*/
        }
 
        .big {
            display: none;
            position: absolute;
            top: 0;
            left: 410px;
            width: 500px;
            height: 500px;
            border: 1px solid #ccc;
            overflow: hidden;
            z-index: 999;
        }
 
        .big img {
            /* 一定要给.big下的img定位属性它的位置才能随着遮罩层的移动而移动哦 */
            position: absolute;
            top: 0;
            left: 0;
        }
</style>

JavaScript行为逻辑:


<script>
        window.addEventListener('load', function () {
            // 1.获取元素
            var box = document.querySelector('.box');
            var mask = document.querySelector('.mask');
            var big = document.querySelector('.big');
 
            // 2.注册事件
            // (1)box鼠标经过即显示出遮罩层mask和右侧大图 onmouseover  
            box.addEventListener('mouseover', function () {
                mask.style.display = 'block';
                big.style.display = 'block';
            })
            // (2)box鼠标离开即隐藏遮罩层mask和右侧大图 onmouseout  
            box.addEventListener('mouseout', function () {
                mask.style.display = 'none';
                big.style.display = 'none';
            })
            // (3)让mask遮罩层随着鼠标移动(此事件要写在获得鼠标的情况下)
            box.addEventListener('mousemove', function (e) {
                // (1). 先计算出鼠标在盒子内的坐标,鼠标在盒子里的坐标=鼠标在屏幕中的坐标-盒子的offsetLeft/offsetTop
                var x = e.pageX - this.offsetLeft;
                var y = e.pageY - this.offsetTop;
                // (2) 鼠标在遮罩层中应该处于中心的位置,所以还要把鼠标从遮罩层的左上角往右往下移动遮罩层宽高的一半才行,即鼠标在盒子里的坐标减去盒子高度的一半和宽度的一半就是我们mask 的最终 left 和top值了
                var maskX = x - mask.offsetWidth / 2;   // 鼠标位置在遮罩层水平中间
                var maskY = y - mask.offsetHeight / 2;   // 鼠标位置在遮罩层垂直中间
 
                // (3) 我们mask 遮罩层水平移动的距离即maskX= 遮罩层的父盒子的宽-遮罩层的宽,而遮罩层垂直移动的距离即maskY= 遮罩层的父盒子的高-遮罩层的高
                // (4) 如果x 坐标小于了0 就让他停在0 的位置
                // 遮挡层的最大移动距离= 遮罩层的父盒子的宽-遮罩层的宽(因为此案例的遮罩层是一个正方形,所以水平和垂直的范围是一致的)
                var maskMax = box.offsetWidth - mask.offsetWidth;   // 遮罩层的最大移动距离
                // 判断限定遮罩层的可移动范围:水平可移动范围:
                maskX <= 0 ? maskX = 0 : maskX = maskX;     // 水平最小可移动范围
                maskX >= maskMax ? maskX = maskMax : maskX = maskX; // 水平最小大可移动范围
                // 判断限定遮罩层的可移动范围:垂直可移动范围:
                maskY <= 0 ? maskY = 0 : maskY = maskY;     // 垂直最小可移动范围
                maskY >= maskMax ? maskY = maskMax : maskY = maskY; // 垂直最大可移动范围
                // 将鼠标的坐标值给mask的left和top(mask是有定位的)注意要加px单位!!!
                mask.style.left = maskX + 'px';
                mask.style.top = maskY + 'px';
                // (5)让右侧大图随着遮罩层移动而移动
                // 大图片的移动距离 = 遮挡层移动距离 * 大图片最大移动距离 / 遮挡层的最大移动距离
                // 获取大图
                var bigImg = big.querySelector('img');
                // 大图片最大移动距离
                var bigMax = bigImg.offsetWidth - big.offsetWidth;
                // 大图片的移动距离 X Y
                var bigX = maskX * bigMax / maskMax;
                var bigY = maskY * bigMax / maskMax;
                // 注意:1.bigImg获取到的元素需要有CSS定位属性才能移动位置的,没有定位位置是不会变的哦
                // 2.大图的移动和遮罩层移动的方向是相反的哦,因为遮罩层往左移动时实际上大图是要往右移动的,所以值是负数
                bigImg.style.left = -bigX + 'px';
                bigImg.style.top = -bigY + 'px';
            })
 
        })
</script>

效果动态展示:

1. 程序初始运行状态,用户鼠标尚未接触左侧小图(.box)时:

以下是实现该功能的具体代码部分:

2. 鼠标经过左侧小图区域时:

以下是实现该功能的具体代码部分:

3. 鼠标在左侧小图(.box)内部移动时:

以下是实现该功能的具体代码部分:

案例核心知识点及细节说明:

1. HTML结构部分:主要结构由一个外层大div(即.box)包裹一张图片(左侧小图)以及两个内部div组成(分别为遮罩层和右侧显示大图的容器)。这三个元素中,默认仅左侧小图可见,遮罩层和大图容器均设置为隐藏状态(display: none;)。此外,遮罩层和大图容器均通过绝对定位(子绝父相)放置于指定位置。需注意,右侧大图的z-index属性需设置较高值,因为该区域原本可能包含其他内容,若不提升层级,大图可能被遮挡。

2. CSS样式部分:样式设置遵循常规规范,唯一关键点在于大图内部的img元素必须设置position: absolute;绝对定位。只有这样,JavaScript才能通过动态修改left和top属性来移动图片,从而实现大图随小图内鼠标移动而同步移动的效果。

3. JavaScript部分:主要涉及鼠标经过事件(onmouseover)、鼠标离开事件(onmouseout)和鼠标移动事件(onmousemove)。需注意,若使用addEventListener()注册事件,则无需添加'on'前缀,且事件名需用引号包裹。核心思路是为最外层大盒子(.box)绑定鼠标经过事件,鼠标进入时使遮罩层和右侧大图显示(display: block;),鼠标离开时隐藏(display: none;)。随后为.box绑定鼠标移动事件,在鼠标内部移动时,首先获取鼠标相对于.box的坐标(X坐标通过e.pageX - box.offsetLeft计算,Y坐标同理)。得到鼠标坐标后决定遮罩层位置,但需注意,鼠标坐标对应的是遮罩层的中心点,因此需将得到的坐标值分别加上遮罩层高度和宽度的一半,赋值给遮罩层,这样确定的才是遮罩层左上角的正确坐标。

4. 遮罩层已能随鼠标移动,但还需限制其移动范围,确保不超出父盒子。因此需添加判断逻辑:若遮罩层向左移动至0,则停止向左;向右移动的最大距离由遮罩层与父盒子(.box)的宽度差决定,即移动范围是从0到(box.offsetWidth - mask.offsetWidth),也就是父盒子宽度减去遮罩层宽度。

5. 遮罩层移动范围限制完成后,接下来处理右侧大图的显示,这里涉及一个核心算法:

以下是实现该功能的具体代码部分:

大图移动距离与遮罩层移动距离存在比例关系,即遮罩层移动多少,大图按相同比例移动(例如遮罩层移动1px,大图移动2px,则遮罩层移动2px时,大图应移动4px)。通过该公式计算出小图移动时大图对应的移动距离,并将此数据赋值给右侧大图(div下的img),通过style.left和style.top改变图片位置(注意值需添加px单位)。需特别注意,大图移动方向与遮罩层移动方向相反:遮罩层向右移动时,大图实际向左移动(以展示其右侧区域),因此给left和top赋的值需取负号。

至此,基本介绍了本案例涉及的知识点及注意事项。建议结合代码(内含详细注释)查看,以更清晰地理解编程步骤及实现思路。本案例采用纯JS底层代码实现(存在诸多可优化空间),或许存在更简单的方法,但使用基础JS代码能更直观地理解核心逻辑与算法。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

作者最新文章