文章目录
- [一、offset 属性案例 - 放大镜效果](#一、offset 属性案例 - 放大镜效果)
-
- [1、 需求说明](#1、 需求说明)
- [2、HTML 结构](#2、HTML 结构)
- [3、CSS 样式](#3、CSS 样式)
-
- [① 清除内外边距](#① 清除内外边距)
- [② 小图容器样式](#② 小图容器样式)
- [③ 遮挡层样式](#③ 遮挡层样式)
- [④ 大图容器样式](#④ 大图容器样式)
- [⑤ 大图容器内的图片样式](#⑤ 大图容器内的图片样式)
- [4、设置 window 对象 onload 事件](#4、设置 window 对象 onload 事件)
- [5、显示 / 隐藏 遮挡层和大图容器](#5、显示 / 隐藏 遮挡层和大图容器)
- 6、计算鼠标在小图容器中的坐标
- 7、计算小图容器中遮挡层的位置
- 8、大图片显示设置
- [二、 完整代码示例](#二、 完整代码示例)
-
- [1、 代码示例](#1、 代码示例)
- 2、图片资源
- [3、 执行效果](#3、 执行效果)
一、offset 属性案例 - 放大镜效果
1、 需求说明
实现如下放大镜效果 :
- 小图容器 盒子 : 左侧是 小图容器 盒子 , 显示 小图片 ;
- 遮挡层 : 在 小图容器 盒子上方 , 有一个 黄色的 遮挡层 ;
- 遮挡层显示与隐藏 : 鼠标 进入 小图容器 盒子区域 显示遮挡层 , 鼠标 离开 小图容器 盒子区域 隐藏遮挡层 ;
- 遮挡层移动 : 遮挡层 随鼠标 移动 , 且 遮挡层 移动区域 被限制在 小图容器 盒子 范围内 ;
- 大图容器 盒子 : 右侧显示 大图容器盒子 , 其中显示大图片 , 并且只能 显示一部分大图片 ;
- 大图容器显示范围 : 大图容器盒子 中 显示的大图片 , 随着 遮挡层 移动而移动 ;

2、HTML 结构
小图容器 <div class="small"> 用于 承载小图、遮罩层、大图容器的父容器 , 对应 CSS 中的 .small 类 ;
小图图片 <img src="small.png" alt=""> 充满整个 小图容器 , 展示需要放大的原始小图 ;
遮罩层 <div class="mask"></div> 是 鼠标拖动时选中小图的放大区域 , 对应 CSS 中的 .mask 类 ;
大图容器 <div class="big"> 展示遮罩层对应区域的放大图 , 对应 CSS 中的 .big 类 , 该容器 实际上 在 小图容器 右侧 ;
大图图片 <img src="big.jpg" alt="" class="bigImg"> 需要放大的高清图 , 对应CSS中的 .big img 样式 , 该盒子 大于 大图容器 盒子大小 ;
HTML 结构 部分代码示例 :
html
<!-- 小图容器:承载小图、遮罩层、大图容器的父容器,对应CSS中的.small类 -->
<div class="small">
<!-- 小图图片:展示需要放大的原始小图 -->
<img src="small.png" alt="">
<!-- 遮罩层:鼠标拖动时选中小图的放大区域,对应CSS中的.mask类 -->
<div class="mask"></div>
<!-- 大图容器:展示遮罩层对应区域的放大图,对应CSS中的.big类 -->
<div class="big">
<!-- 大图图片:需要放大的高清图,对应CSS中的.big img样式 -->
<img src="big.jpg" alt="" class="bigImg">
</div>
</div>
3、CSS 样式
① 清除内外边距
使用 通配符选择器 * 选中页面中所有 HTML 元素 , 清除所有元素默认的 外边距 和 内边距 ;
css
* {
/* 通配符选择器:选中页面中所有HTML元素 */
/* 清除所有元素默认的外边距 */
margin: 0;
/* 清除所有元素默认的内边距 */
padding: 0;
}
② 小图容器样式
小图容器 是 放大镜效果的 小图展示区域 ,
该容器 作为内部 绝对定位元素 ( mask、big ) 的 定位父级 , 根据 " 子绝父相 " 原则 , 该容器 应该设置 相对定位 属性 ;
代码示例 :
css
.small {
/* 小图容器样式:放大镜效果的小图展示区域 */
/* 相对定位:作为内部绝对定位元素(mask、big)的定位父级 */
position: relative;
/* 设置小图容器的宽度为398像素 */
width: 398px;
/* 设置小图容器的高度为398像素 */
height: 398px;
/* 设置容器边框:1像素、实线、浅灰色 */
border: 1px solid #ccc;
}

③ 遮挡层样式
遮挡层 是 鼠标在小图上拖动的半透明遮罩 , 默认是 隐藏的 ;
遮挡层 的 位置 需要像素级移动 , 因此需要 设置为 绝对定位 或 固定定位 , 由于是 相对父元素 移动 , 而不是 相对浏览器页面 移动 , 因此这里 优先使用 绝对定位 , 父容器 设置 相对定位 ;
遮挡层 在 鼠标经过 small 小图容器 元素时 才显示 , 在 鼠标离开 small 小图容器 元素时 隐藏 ;
CSS 样式代码示例 :
css
.mask {
/* 遮挡层样式:鼠标在小图上拖动的半透明遮罩 */
/* 默认隐藏遮罩层:初始状态不显示 */
display: none;
/* 绝对定位:相对于父元素.small进行定位 */
position: absolute;
/* 遮罩层初始顶部偏移量:0像素(与父元素顶部对齐) */
top: 0;
/* 遮罩层初始左侧偏移量:0像素(与父元素左侧对齐) */
left: 0;
/* 遮罩层宽度:300像素 */
width: 300px;
/* 遮罩层高度:300像素 */
height: 300px;
/* 遮罩层背景色:淡黄色(放大镜选中区域的标识色) */
background: #FEDE4F;
/* 遮罩层透明度:0.5(半透明效果,能看到下方的小图) */
opacity: .5;
/* 遮罩层边框:1像素、实线、浅灰色 */
border: 1px solid #ccc;
/* 鼠标悬浮在遮罩层上时的光标样式:移动光标(提示可拖动) */
cursor: move;
}

④ 大图容器样式
大图容器 是 放大镜效果的大图展示区域 ;
该 大图容器 需要 使用 绝对定位 , 需要 相对于父元素 .small 进行定位 ;
大图容器 相对于 小图容器 设置 左侧偏移量 410 像素 , 小图容器 398 像素 , 与 小图容器 右侧 留出12 像素间距 ;
部分代码示例 :
css
.big {
/* 大图容器样式:放大镜效果的大图展示区域 */
/* 默认隐藏大图容器:初始状态不显示 */
display: none;
/* 绝对定位:相对于父元素.small进行定位 */
position: absolute;
/* 大图容器左侧偏移量:410像素(与小图容器右侧留出10像素间距) */
left: 410px;
/* 大图容器顶部偏移量:0像素(与小图容器顶部对齐) */
top: 0;
/* 大图容器宽度:500像素 */
width: 500px;
/* 大图容器高度:500像素 */
height: 500px;
/* 大图容器背景色:粉色(仅占位,实际会被大图覆盖) */
background-color: pink;
/* 层级设置:999(确保大图容器在其他元素上方显示) */
z-index: 999;
/* 大图容器边框:1像素、实线、浅灰色 */
border: 1px solid #ccc;
/* 溢出隐藏:大图超出容器的部分不显示(仅展示对应遮罩区域的放大内容) */
overflow: hidden;
}
⑤ 大图容器内的图片样式
大图容器内的图片 很大 , 大图容器 只能显示 部分图片 , 默认显示状态 只能显示 左上角 部分 图片区域 ;
代码示例 :
css
.big img {
/* 大图容器内的图片样式 */
/* 绝对定位:方便通过top/left属性调整大图位置,实现跟随遮罩移动 */
position: absolute;
/* 大图初始顶部偏移量:0像素 */
top: 0;
/* 大图初始左侧偏移量:0像素 */
left: 0;
}
4、设置 window 对象 onload 事件
为 BOM 的 window 对象添加 load 事件 , 等页面中所有的资源加载完毕后 , 才触发 onload 事件回调函数 ;
javascript
window.addEventListener('load', function() {
5、显示 / 隐藏 遮挡层和大图容器
鼠标经过 small 小图容器 元素时 才显示 mask 遮挡层 和 big 大盒子 , 鼠标离开 small 小图容器 元素时 隐藏 mask 遮挡层 和 big 大盒子 ;
javascript
// 鼠标经过 small 小图容器 元素时 才显示 mask 遮挡层 和 big 大盒子
small.addEventListener('mouseover', function() {
mask.style.display = 'block';
big.style.display = 'block';
});
// 鼠标离开 small 小图容器 元素时 隐藏 mask 遮挡层 和 big 大盒子
small.addEventListener('mouseout', function() {
mask.style.display = 'none';
big.style.display = 'none';
});
6、计算鼠标在小图容器中的坐标
鼠标 在 下图容器 中 移动的时候 , 让 遮挡层 盒子跟着鼠标来走 , 需要为 小图容器 设置 mousemove 事件 ;
无法直接获取 鼠标指针 相对于 指定盒子内部 的 指针位置 ;
参考 【Web APIs】元素偏移量 offset 系列属性 ③ ( offset 属性案例 - 计算鼠标指针在盒子内位置 | offset 属性案例 - 鼠标拖动盒子移动 ) 博客 , 计算 鼠标指针 在 指定 盒子模型 中的 位置 ;
- 首先 , 计算 鼠标在页面中的坐标 ( e.pageX, e.pageY ) ;
- 然后 , 计算 盒子在页面中的偏移 ( this.offsetLeft, this.offsetTop ) ;
- 最后 , 计算 鼠标在盒子内的坐标 ( e.pageX - this.offsetLeft, e.pageY - box.this ) ;
部分代码示例 :
javascript
// 鼠标移动的时候 , 让 遮挡层 盒子跟着鼠标来走
small.addEventListener('mousemove', function(e) {
// 2. 计算出 鼠标 在 小图容器 盒子内的坐标
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
7、计算小图容器中遮挡层的位置
鼠标 在 小图容器 中 , 鼠标指针的位置 对应的事 遮挡层 的 中心位置 ;
计算 遮挡层 左上角位置 , 需要 鼠标 位置 减去 遮挡层一半宽高 ;
javascript
var maskX = x - mask.offsetWidth / 2;
var maskY = y - mask.offsetHeight / 2;
此外 , 还需要 处理 遮挡层 越界问题 , 遮挡层 移动 , 需要再 小图容器 范围内进行 , 不能超出边界 ;
遮挡层 的 水平方向最小值 left 肯定是 0 ,
然后 计算 遮挡层 的 水平方向 和 垂直方向 的 最大移动距离 ,
由于 遮挡层 和 外层盒子 是正方形 , 因此 该值也可是 垂直方向 的 最大移动距离 ;
javascript
var maskMax = small.offsetWidth - mask.offsetWidth;
处理水平方向上的越界问题 ;
javascript
if (maskX <= 0) {
maskX = 0;
} else if (maskX >= maskMax) {
maskX = maskMax;
}
处理垂直方向上的越界问题 ;
javascript
if (maskY <= 0) {
maskY = 0;
} else if (maskY >= maskMax) {
maskY = maskMax;
}
最终通过 mask.style 设置 遮挡层 的 位置 ;
javascript
mask.style.left = maskX + 'px';
mask.style.top = maskY + 'px';
部分代码示例 :
javascript
// 3. 计算 遮挡层 位置
// 如果直接将 x, y 坐标设置给 mask.style.left 和 mask.style.top , 遮挡层 左上角 就是鼠标位置
// 这里需要设置 鼠标位置 是 遮挡层 中心位置
// 计算 遮挡层左上角位置 , 需要 鼠标 位置 减去 遮挡层一半宽高
var maskX = x - mask.offsetWidth / 2;
var maskY = y - mask.offsetHeight / 2;
// 4. 处理 遮挡层越界问题
// 遮挡层 的 水平方向 的 最大移动距离
// 由于 遮挡层 和 外层盒子 是正方形 , 因此 该值也可是 垂直方向 的 最大移动距离
var maskMax = small.offsetWidth - mask.offsetWidth;
// 处理水平方向上的越界问题
if (maskX <= 0) {
maskX = 0;
} else if (maskX >= maskMax) {
maskX = maskMax;
}
// 处理垂直方向上的越界问题
if (maskY <= 0) {
maskY = 0;
} else if (maskY >= maskMax) {
maskY = maskMax;
}
// 5. 设置遮挡层的偏移距离
mask.style.left = maskX + 'px';
mask.style.top = maskY + 'px';
8、大图片显示设置
使用如下公式 , 计算 大图片 的 移动距离 :
遮挡层移动距离 / 遮挡层的最大移动距离 = 大图片的移动距离 / 大图片最大移动距离
原理分析 :
鼠标指针 的位置 , 就是 遮挡层 的 中心位置 , 此时该中心位置 的比例是 " 遮挡层移动距离 / 遮挡层的最大移动距离 " , 对应 显示的 大图片 的中心位置 也是这个比例 ,
" 遮挡层移动距离 / 遮挡层的最大移动距离 " 比例值 是 确定的 , 可以计算出来 ;
大图片显示的 比例值 " 大图片的移动距离 / 大图片最大移动距离 " 等于 上面的 比例 ;
大图片最大移动距离 是确定的 , 现在需要计算出 大图片的移动距离 , 因此就有了如下 最终计算公式 ;
最终的计算公式 :
大图片的移动距离 = 遮挡层移动距离 * 大图片最大移动距离 / 遮挡层的最大移动距离
部分代码示例 :
javascript
// 大图元素
var bigImg = document.querySelector('.bigImg');
// 大图片最大移动距离
var bigMax = bigImg.offsetWidth - big.offsetWidth;
// 大图片的移动距离 X Y 计算
// 大图片的水平方向移动距离 = 遮挡层水平移动距离 * 大图片最大移动距离 / 遮挡层的最大移动距离
var bigX = maskX * bigMax / maskMax;
// 大图片的垂直方向移动距离 = 遮挡层垂直移动距离 * 大图片最大移动距离 / 遮挡层的最大移动距离
var bigY = maskY * bigMax / maskMax;
// 大图的移动距离是反方向的
bigImg.style.left = -bigX + 'px';
bigImg.style.top = -bigY + 'px';
二、 完整代码示例
1、 代码示例
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>放大镜效果</title>
<style>
* {
/* 通配符选择器:选中页面中所有HTML元素 */
/* 清除所有元素默认的外边距 */
margin: 0;
/* 清除所有元素默认的内边距 */
padding: 0;
}
.small {
/* 小图容器样式:放大镜效果的小图展示区域 */
/* 相对定位:作为内部绝对定位元素(mask、big)的定位父级 */
position: relative;
/* 设置小图容器的宽度为398像素 */
width: 398px;
/* 设置小图容器的高度为398像素 */
height: 398px;
/* 设置容器边框:1像素、实线、浅灰色 */
border: 1px solid #ccc;
}
.mask {
/* 遮罩层样式:鼠标在小图上拖动的半透明遮罩 */
/* 默认隐藏遮罩层:初始状态不显示 */
display: none;
/* 绝对定位:相对于父元素.small进行定位 */
position: absolute;
/* 遮罩层初始顶部偏移量:0像素(与父元素顶部对齐) */
top: 0;
/* 遮罩层初始左侧偏移量:0像素(与父元素左侧对齐) */
left: 0;
/* 遮罩层宽度:300像素 */
width: 300px;
/* 遮罩层高度:300像素 */
height: 300px;
/* 遮罩层背景色:淡黄色(放大镜选中区域的标识色) */
background: #FEDE4F;
/* 遮罩层透明度:0.5(半透明效果,能看到下方的小图) */
opacity: .5;
/* 遮罩层边框:1像素、实线、浅灰色 */
border: 1px solid #ccc;
/* 鼠标悬浮在遮罩层上时的光标样式:移动光标(提示可拖动) */
cursor: move;
}
.big {
/* 大图容器样式:放大镜效果的大图展示区域 */
/* 默认隐藏大图容器:初始状态不显示 */
display: none;
/* 绝对定位:相对于父元素.small进行定位 */
position: absolute;
/* 大图容器左侧偏移量:410像素(与小图容器右侧留出10像素间距) */
left: 410px;
/* 大图容器顶部偏移量:0像素(与小图容器顶部对齐) */
top: 0;
/* 大图容器宽度:500像素 */
width: 500px;
/* 大图容器高度:500像素 */
height: 500px;
/* 大图容器背景色:粉色(仅占位,实际会被大图覆盖) */
background-color: pink;
/* 层级设置:999(确保大图容器在其他元素上方显示) */
z-index: 999;
/* 大图容器边框:1像素、实线、浅灰色 */
border: 1px solid #ccc;
/* 溢出隐藏:大图超出容器的部分不显示(仅展示对应遮罩区域的放大内容) */
overflow: hidden;
}
.big img {
/* 大图容器内的图片样式 */
/* 绝对定位:方便通过top/left属性调整大图位置,实现跟随遮罩移动 */
position: absolute;
/* 大图初始顶部偏移量:0像素 */
top: 0;
/* 大图初始左侧偏移量:0像素 */
left: 0;
}
</style>
<script>
// 为 BOM 的 window 对象添加 load 事件 , 等页面中所有的资源加载完毕后 , 才触发 onload 事件回调函数
window.addEventListener('load', function() {
// 事件源 , 需要再该 元素 上添加 鼠标移动事件
var small = document.querySelector('.small');
// 图像上可移动的半透明 遮挡层
var mask = document.querySelector('.mask');
// 右侧显示大图的元素
var big = document.querySelector('.big');
// 鼠标经过 preview_img 元素时 才显示 mask 遮挡层 和 big 大盒子
small.addEventListener('mouseover', function() {
mask.style.display = 'block';
big.style.display = 'block';
});
// 鼠标离开 preview_img 元素时 隐藏 mask 遮挡层 和 big 大盒子
small.addEventListener('mouseout', function() {
mask.style.display = 'none';
big.style.display = 'none';
});
// 2. 鼠标移动的时候,让 遮挡层 盒子跟着鼠标来走
small.addEventListener('mousemove', function(e) {
// (1). 先计算出鼠标在盒子内的坐标
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
// 如果直接将 x, y 坐标设置给 mask.style.left 和 mask.style.top , 遮挡层 左上角 就是鼠标位置
// 这里需要设置 鼠标位置 是 遮挡层 中心位置
// 计算 遮挡层左上角位置 , 需要 鼠标 位置 减去 遮挡层一半宽高
// (2) 减去盒子高度 300的一半 是 150 就是我们mask 的最终 left 和top值了
// (3) 我们mask 移动的距离
var maskX = x - mask.offsetWidth / 2;
var maskY = y - mask.offsetHeight / 2;
// 处理 遮挡层越界问题
// (4) 如果x 坐标小于了0 就让他停在0 的位置
// 遮挡层 的 水平方向 的 最大移动距离
// 由于 遮挡层 和 外层盒子 是正方形 , 因此 该值也可是 垂直方向 的 最大移动距离
var maskMax = small.offsetWidth - mask.offsetWidth;
// 处理水平方向上的越界问题
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;
// 大图片的移动距离 X Y 计算
// 大图片的水平方向移动距离 = 遮挡层水平移动距离 * 大图片最大移动距离 / 遮挡层的最大移动距离
var bigX = maskX * bigMax / maskMax;
// 大图片的垂直方向移动距离 = 遮挡层垂直移动距离 * 大图片最大移动距离 / 遮挡层的最大移动距离
var bigY = maskY * bigMax / maskMax;
// 大图的移动距离是反方向的
bigImg.style.left = -bigX + 'px';
bigImg.style.top = -bigY + 'px';
});
});
</script>
</head>
<body>
<!-- 小图容器:承载小图、遮罩层、大图容器的父容器,对应CSS中的.small类 -->
<div class="small">
<!-- 小图图片:展示需要放大的原始小图 -->
<img src="small.png" alt="">
<!-- 遮罩层:鼠标拖动时选中小图的放大区域,对应CSS中的.mask类 -->
<div class="mask"></div>
<!-- 大图容器:展示遮罩层对应区域的放大图,对应CSS中的.big类 -->
<div class="big">
<!-- 大图图片:需要放大的高清图,对应CSS中的.big img样式 -->
<img src="big.jpg" alt="" class="bigImg">
</div>
</div>
</body>
</html>
2、图片资源
小图片:

大图片 :

3、 执行效果
执行效果 :
进入界面后 , 展示如下效果 :

完整执行效果如下 :
