背景知识:元素偏移量 offset
offset 翻译为 偏移量 ,使用 offset 的相关属性可以动态的得到该元素的位置(偏移)、大小等。
- 获得元素距离带有定位父元素的位置
- 获得元素自身的大小(宽度和高度)
- 注意:返回的数值都不带单位
常见的属性有:
offset系列属性 | 作用 |
element.offsetParent | 返回作为该元素带有定位的父级元素 如果父级都没有定位则返回body |
element.offsetTop | 返回元素相对带有定位父元素上方的偏移 |
element.offsetLeft | 返回元素相对带有定位父元素左边框的偏移 |
element.offsetWidth | 返回自身包括padding、边框、内容区的宽度,返回数值不带单位 |
element.offsetHeight | 返回自身包括padding、边框、内容区的高度,返回数值不带单位 |
注意区分 offset 和 style 的区别
offset | style |
|
|
案例分析:
① 整个案例可以分为三个功能模块;
② 鼠标经过小图片盒子,黄色的遮挡层和大图片盒子显示,离开隐藏2个盒子功能;
③ 黄色的遮挡层跟随鼠标功能;
④ 移动黄色遮挡层,大图片跟随移动功能。
其中,黄色遮挡层跟随鼠标功能,鼠标的坐标不宜赋值给遮挡层,因为遮挡层坐标是以父盒子(放着商品图片的盒子)为准的。
我们写好HTML和CSS布局后,第一步是实现遮挡层和大图片显示和隐藏功能:建立鼠标事件(mouseover),当鼠标经过父盒子(放着商品小图片的盒子)就显示(display:‘block’),离开(mouseout) 就隐藏。
第二步:让黄色的遮挡层随着鼠标的移动而移动,首先获取鼠标在盒子内的坐标,然后把数值给遮挡层作为其 left 和 top 值。
鼠标在盒子内的坐标 = 鼠标在页面中的坐标 - 盒子在页面中的坐标;(如下示意图:)
注意小细节:此处的盒子(放商品的盒子)要注意其有没有父盒子,若存在父盒子,且有定位,那得到的 offsetLeft 是这个盒子距离其父盒子的距离,而不是距离浏览器的距离。如下图所示:
本案例中放商品的盒子的父盒子不设置定位,故不需要考虑上述的情况。
此时用到鼠标移动事件(mousemove),但发现鼠标不在遮挡层的中央,在黄色遮挡层左上角,处理办法是让黄色遮挡层往上和往左分别移动遮挡层盒子宽高的一半,即鼠标在盒子内的坐标再减去offsetWidth/2 和 offsetHeight/2,得到的就是遮挡层最终的 left 和 top 值了。
但此时又发现,遮挡层并不能在父盒子内移动,却可以在整个浏览器页面移动。
因此,利用判断条件 if 语句,限定遮挡层移动的距离在 0 和最大移动距离之间,
遮挡层的最大移动距离 = 商品小图片盒子的宽度 - 遮挡层盒子的宽度。
最后一步,就是让外边的大图片随着遮挡层的移动也移动,其移动距离可如下求得:
大图片的移动距离 = 遮挡层移动距离 * 大图片最大移动距离 / 遮挡层的最大移动距离
这里大图片的最大移动距离和前面的遮挡层的最大移动距离计算有区别,因为大图片的宽高都要大于装大图片盒子的宽高,所以,
大图片的最大移动距离 = 大图片的宽高 - 大图片盒子的宽高;
由于上述的装大图片和小图片的盒子为正方形,因此 width = height ,即求的宽width 就能直接求最大的移动距离了。
这里还有一点注意:必须给大图片设置定位position: absolute,否则不会移动。
最后,因为遮挡层与大图移动是相反方向的,因此要给大图的移动距离前加上:“ - ”
至此,仿京东购物界面放大镜效果基本实现,效果图如下可见
JavaScript 部分:
<script>
window.addEventListener('load', function () {
var preview_img = document.querySelector('.preview_img');
var mask = document.querySelector('.mask');
var big = document.querySelector('.big');
// 1. 当鼠标经过 preview_img 就显示和隐藏 mask 遮挡层和 big 大盒子
preview_img.addEventListener('mouseover', function () {
mask.style.display = 'block';
big.style.display = 'block';
})
preview_img.addEventListener('mouseout', function () {
mask.style.display = 'none';
big.style.display = 'none';
})
// 2.鼠标移动的时候,让黄色的盒子跟着鼠标走来走去
preview_img.addEventListener('mousemove', function (e) {
// (1).先计算鼠标在盒子内的坐标
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
// (2)盒子的高度 300 的一半 150 就是 mask 的最终 left 和 top 值
// (3) mask 移动的距离
var maskX = x - mask.offsetWidth / 2;
var maskY = y - mask.offsetHeight / 2;
// 遮挡层的最大移动距离:
var maskMax = preview_img.offsetWidth - mask.offsetWidth;
// (4) 如果 x 坐标小于0就让其停在0的位置
if (maskX <= 0) {
maskX = 0;
} else if (maskX >= maskMax) {
maskX = maskMax;
}
if (maskY <= 0) {
maskY = 0;
} else if (maskY >= maskMax) {
maskY = maskMax;
}
mask.style.left = maskX + 'px';
mask.style.top = maskY + 'px';
// 3. 大图片的移动距离 = 遮挡层移动距离 * 大图片最大移动距离 / 遮挡层的最大移动距离
var bigImg = document.querySelector('.bigImg');
// 大图片最大移动距离:
var bigMax = bigImg.offsetWidth - big.offsetWidth;
// 大图片的移动距离:
var bigX = maskX * bigMax / maskMax;
var bigY = maskY * bigMax / maskMax;
bigImg.style.left = -bigX + 'px';
bigImg.style.top = -bigY + 'px';
})
})
</script>
最终效果图: