首先看看某东的效果:
这个案例可以分为三个功能模块:
- 鼠标经过小图片的盒子,遮罩层和大图片盒子显示,离开隐藏遮罩层和大图片盒子。
- 遮罩层跟随鼠标移动。
- 移动遮罩层,大图片跟随移动。
要实现这个案例,我们需要用到下面几个知识点:
属性 | 作用 |
---|---|
element.offsetTop | 返回元素相对于带有定位父元素上边框的偏移量 |
element.offsetLeft | 返回元素相对于带有定位父元素左边框的偏移量 |
element.offsetWidth | 返回自身包括padding、边框、内容区的宽度,返回数值不带单位。 |
element.offsetHeight | 返回自身包括padding、边框、内容区的高度,返回数值不带单位。 |
event.pageX | 返回鼠标相对于整个文档的x坐标,返回数值不带单位 |
event.pageY | 返回鼠标相对于整个文档的y坐标,返回数值不带单位 |
首先先搭建页面布局:
<div class="box">
<!-- 小盒子,存放一张小图片 -->
<img src="./chuying.jpg">
<!-- 遮罩层 -->
<div class="mask"></div>
<!-- 大盒子以及大图片 -->
<div class="big">
<img src="./chuying.jpg">
</div>
</div>
CSS:
.box {
position: relative;
width: 300px;
height: 300px;
cursor: move;
}
.box img {
width: 100%;
}
.box .mask {
display: none;
position: absolute;
width: 150px;
height: 150px;
left: 0;
top: 0;
background-color: rgba(135, 206, 235, 0.5);
border: 1px solid #cccccc;
}
.big {
display: none;
position: absolute;
width: 600px;
height: 600px;
top: 0;
left: 310px;
border: 1px solid #ccc;
overflow: hidden;
}
.big img {
position: absolute;
width: 800px;
height: 800px;
left: 0;
top: 0;
}
模块一:
鼠标经过小盒子,遮罩层和大图片盒子显示(display: block),这里有一个鼠标经过(mouseover)事件,鼠标离开(mouseout)小盒子,遮罩层和大图片盒子隐藏(display: none)。
这里只要给小盒子(.box)添加相应的鼠标事件,然后修改遮罩层和大图片盒子的display属性的值即可。
JS代码:
// 首先获取小盒子、遮罩层、大盒子三个元素
var box = document.querySelector('.box');
var mask = document.querySelector('.mask');
var big = document.querySelector('.big');
// 鼠标经过 box 就显示 mask遮罩层和 big 大盒子
box.addEventListener('mouseover', function () {
mask.style.display = 'block';
big.style.display = 'block';
})
// 鼠标离开 box 就隐藏 mask遮罩层和 big 大盒子
box.addEventListener('mouseout', function () {
mask.style.display = 'none';
big.style.display = 'none';
})
模块一完成。
模块二:
遮罩层要跟随鼠标移动,首先要得到鼠标在小盒子里的位置,然后将鼠标在小盒子里的坐标分别给遮罩层的left和top。
box.addEventListener('mousemove', function(e) {
// 获得鼠标在小盒子内的位置
var mouseX = e.pageX - this.offsetLeft;
var mouseY = e.pageY - this.offsetTop;
// 将鼠标的坐标赋值给遮罩层的left top
mask.style.left = mouseX + 'px';
mask.style.top = mouseY + 'px';
})
此时就有一个问题,鼠标总是处于遮罩层的左上角:
想要鼠标在遮罩层的中间,修改鼠标的坐标不现实,我们可以修改遮罩层的left和top值,如果我们将left和top值分别减去遮罩层宽高的一半,就相当于将遮罩层往左和往上移动了自己的宽高的一半,此时鼠标的位置没变,那么遮罩层移动后的位置,鼠标刚好位于遮罩层的中心。
box.addEventListener('mousemove', function(e) {
// 获得鼠标在小盒子内的位置
var mouseX = e.pageX - this.offsetLeft;
var mouseY = e.pageY - this.offsetTop;
// 将鼠标坐标减去遮罩层宽高的一半,得到新的遮罩层的偏移量
var maskX = mouseX - mask.offsetWidth / 2;
var maskY = mouseY - mask.offsetHeight / 2;
// 设置遮罩层的偏移量
mask.style.left = maskX + 'px';
mask.style.top = maskY + 'px';
})
此时,鼠标在遮罩层的中间了,同时遮罩层也跟随鼠标了,但是又有一个新的问题,遮罩层能移出小盒子:
要解决这个问题,就得设置遮罩层跟随鼠标移动时的边界,当鼠标的坐标减去遮罩层宽度的一半小于0时,就应该让遮罩层的left = 0;当鼠标的坐标减去遮罩层高度的一半小于0时,就应该让遮罩层的top = 0;那么遮罩层的最大偏移量就应该是小盒子的宽高减去遮罩层的宽高。
box.addEventListener('mousemove', function(e) {
// 获得鼠标在小盒子内的位置
var mouseX = e.pageX - this.offsetLeft;
var mouseY = e.pageY - this.offsetTop;
// 将鼠标坐标减去遮罩层宽高的一半,得到新的遮罩层的偏移量
var maskX = mouseX - mask.offsetWidth / 2;
var maskY = mouseY - mask.offsetHeight / 2;
// 遮罩层的最大的移动距离
var maskXMax = this.offsetWidth - mask.offsetWidth;
var maskYMax = this.offsetHeight - mask.offsetHeight;
// 设置移动边界
if (maskX < 0) {
maskX = 0;
} else if (maskX >= maskXMax) {
maskX = maskXMax;
}
if (maskY < 0) {
maskY = 0;
} else if (maskY >= maskYMax) {
maskY = maskYMax;
}
// 设置遮罩层的偏移量
mask.style.left = maskX + 'px';
mask.style.top = maskY + 'px';
})
模块二完成。
模块三:
移动遮罩层,大图片跟随移动呈现放大的效果。要想实现这个效果,就要满足遮罩层的移动距离:遮罩层的最大移动距离 = 大图片的移动距离:大图片的最大移动距离这个条件。这个条件中,遮罩层的移动距离、遮罩层的最大移动距离、大图片的最大移动距离这三个参数,我们都是可求或已经求得了,那么大图片的移动距离 = 遮罩层的移动距离 * 大图片的最大移动距离 / 遮罩层的最大移动距离。
在模块二的基础上,添加下面代码片段。
// 获取大图片
var bigImg = document.querySelector('.big img');
// 计算大图片的移动距离
var bigImgX = maskX * (big.offsetWidth - bigImg.offsetWidth) / maskXMax;
var bigImgY = maskY * (big.offsetHeight - bigImg.offsetHeight) / maskYMax;
// 设置大图片的偏移量
bigImg.style.left = bigImgX + 'px';
bigImg.style.top = bigImgY + 'px';
模块三完成。
案例的完整的JS代码:
// 首先获取小盒子、遮罩层、大盒子三个元素
var box = document.querySelector('.box');
var mask = document.querySelector('.mask');
var big = document.querySelector('.big');
// 鼠标经过 box 就显示 mask遮罩层和 big 大盒子
box.addEventListener('mouseover', function () {
mask.style.display = 'block';
big.style.display = 'block';
})
// 鼠标离开 box 就隐藏 mask遮罩层和 big 大盒子
box.addEventListener('mouseout', function () {
mask.style.display = 'none';
big.style.display = 'none';
})
box.addEventListener('mousemove', function(e) {
// 获得鼠标在小盒子内的位置
var mouseX = e.pageX - this.offsetLeft;
var mouseY = e.pageY - this.offsetTop;
// 将鼠标坐标减去遮罩层宽高的一半,得到新的遮罩层的偏移量
var maskX = mouseX - mask.offsetWidth / 2;
var maskY = mouseY - mask.offsetHeight / 2;
// 遮罩层的最大的移动距离
var maskXMax = this.offsetWidth - mask.offsetWidth;
var maskYMax = this.offsetHeight - mask.offsetHeight;
// 设置移动边界
if (maskX < 0) {
maskX = 0;
} else if (maskX >= maskXMax) {
maskX = maskXMax;
}
if (maskY < 0) {
maskY = 0;
} else if (maskY >= maskYMax) {
maskY = maskYMax;
}
// 设置遮罩层的偏移量
mask.style.left = maskX + 'px';
mask.style.top = maskY + 'px';
// 获取大图片
var bigImg = document.querySelector('.big img');
// 计算大图片的移动距离
var bigImgX = maskX * (big.offsetWidth - bigImg.offsetWidth) / maskXMax;
var bigImgY = maskY * (big.offsetHeight - bigImg.offsetHeight) / maskYMax;
// 设置大图片的偏移量
bigImg.style.left = bigImgX + 'px';
bigImg.style.top = bigImgY + 'px';
})
最后来看下最终的效果,对比一下某东的效果是否一致。