实现效果
黑色只不过是转gif出问题而已
准备工作
1. 访问该网址,理解我们要弄的放大镜效果,鼠标经过商品图片,显示一个黄色的放大选区,右边显示该选区的大图。
2. 获取商品图片和商品大图
【摩托罗拉moto X30 Pro】摩托罗拉moto X30 Pro 全新骁龙8+ 2亿像素 125W闪充+50W无线充 144Hz曲面臻彩屏 5G手机 12GB+256GB 墨韵黑【行情 报价 价格 评测】-京东
商品图片:
https://img12.360buyimg.com/n1/s450x450_jfs/t1/36890/26/19707/96919/63b05265F4b433f6c/6c7017a0c9caa09a.jpg
商品大图:
https://img12.360buyimg.com//n0/jfs/t1/36890/26/19707/96919/63b05265F4b433f6c/6c7017a0c9caa09a.jpg
代码实现
ps: 标红的地方需要懂
1、项目结构:
2、简单的网页布局
只需要准备左边一个正方形盒子右边一个大正方形盒子即可
3、商品大图在右边大盒子局部显示
商品大图不要设置宽高属性,保留其大图800*800的尺寸,商品大图在右边大盒子局部显示(大图比右盒子大),父盒子 overflow:hidden
效果:
<body>
<div class="left-box">
<img src="./images/small.jpg" alt="">
<div class="right-box">
<img src="./images/big.jpg" alt="">
</div>
</div>
</body>
* {
margin: 0;
padding: 0;
/* 盒子模型:padding和边框都不会撑大盒子 */
box-sizing: border-box;
}
.left-box {
position: relative;
margin-top: 100px;
margin-left: 100px;
width: 400px;
height: 400px;
border: 1px solid #ccc;
}
.left-box>img{
width: 100%;
}
.right-box {
position: absolute;
top: 0;
left: 400px;
width: 540px;
height: 540px;
border: 1px solid #ccc;
/* big-box 下的img不设置宽高,就是显示大图本身大小 800*800 */
/* 父盒子局部显示大图 */
overflow: hidden;
}
4、放大镜选区效果布局
选区在左边盒子里,所以是左边盒子儿子,透明度 opacity: 0.5; 鼠标的样式要变成移动的 cursor: move;
5、放大镜选区 和 右侧大盒子 隐藏
隐藏 display: none;(不保留空间)
6、鼠标经过左边的盒子,显示放大镜选区 和 右侧大盒子。
使用js注册监听鼠标经过mouseover和鼠标离开mouseout事件 addEventListener('mouseover', function() {})
7、选区的移动位置1
放大镜选区跟随鼠标移动,鼠标的移动范围是在左边盒子里,不是在放大镜选区里,所以应该是左边的盒子注册监听鼠标移动事件 addEventListener('mousemove', function() {})
放大镜选区跟随鼠标移动,已知:
- mousemove的event对象存在属性pageX和pageY,表示当前鼠标在整个网页页面中的位置。
- 标签元素存在属性offsetLeft和offsetTop,表示当前元素的位置(相对于有定位的父级,如果不存在有定位的父级,则是body)。
- 标签元素存在属性offsetWidth和offsetHeight,表示当前元素的大小,宽度和高度。
- 标签元素存在属性style,若想改变有定位标签元素的位置,则修改元素的style.left和style.top
- 标签元素的位置,以左基点计算。
计算,求 左盒子里的鼠标相对于左盒子的位置(style.left和style.top):
放大镜选区的盒子 在 左盒子中 的位置 (鼠标在选区盒子左基点)= 当前鼠标在整个网页页面中的位置 - 左盒子的位置
8、选区的移动位置2
放大镜选区跟随鼠标移动优化1: 把鼠标放在放大镜选区的中间(鼠标在页面中的位置不变,把选区盒子往左移动一半,往上移动一半)
计算: 选区的移动距离 = 放大镜选区的盒子 在 左盒子中 的位置(鼠标在选区盒子中间) = 放大镜选区的盒子 在 左盒子中 的位置 (鼠标在选区盒子左基点) -(放大镜选区的大小 / 2)
9、选区的移动范围
放大镜选区跟随鼠标移动优化2,限制选区盒子的移动范围:第8步的移动,会出现选区盒子超出左盒子的现象,所以我们要限制选区盒子的移动范围,这时候鼠标就不需要在放大镜选区中间了。小于最小范围,则使它等于最小范围,超过最大范围,则使它等于最大范围。
超过的图:
限制以后:
范围计算:
最小:选区盒子距离左盒子左边框为0
最大:选区盒子距离左盒子右边框为0,即 左盒子的宽度-选区盒子的宽度
选区的移动:
10、右盒子的大小优化。
放大镜选区以后,右盒子显示大图中的相应区域,再这里要构成一种比例关系(因为是正方形,所以就不写高度宽度,直接写大小):
比例1(显示的比例):选区的大小/左盒子的大小 = 右盒子的大小/大图的大小
所以,css中的已知选区盒子大小 250 、左盒子大小400 、大图大小800,则右盒子的大小为250*800/400 = 500,我们之前布局写了540,所以要改成500;
11、大图的移动
放大镜选区以后,右盒子显示大图中的相应区域,所以应该是大图本身相对着父盒子在移动,为了与放大镜选区一致,所以这里也存在一种比例关系:
比例2(移动距离的比例):选区的移动距离/选区的最大移动距离 = 大图的移动距离 / 大图的最大移动距离
大图的移动距离 = 选区的移动距离 * 大图的最大移动距离 / 选区的最大移动距离
大图的最大移动距离:大图距离右盒子右边框为0,即 大图的宽度-右盒子的宽度
注意别忘了,给右盒子大图做定位,大图才能相对右盒子进行移动。
因为是大图相对着右盒子移动,所以要用负号,大图的区域才会在父盒子中显示。
总结
重点是要知道第7步中的已知,以及计算鼠标在盒子中的位置(相对位置),以及理解两个比例关系,这两个比例关系就是等比放大效果的原因,最后就是css也挺重要的,理解相对定位,配合css,js才能作出特效。
完整代码
<!DOCTYPE html>
<html lang="zh-CN">
<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>仿京东PC网页商品详情的放大镜效果</title>
<link rel="stylesheet" href="./css/index.css">
<script src="./js/magnifier.js"></script>
</head>
<body>
<div class="left-box">
<img src="./images/small.jpg" alt="">
<div class="magnifier-box"></div>
<div class="right-box">
<img src="./images/big.jpg" alt="" class="bigImg">
</div>
</div>
</body>
</html>
* {
margin: 0;
padding: 0;
/* 盒子模型:padding和边框都不会撑大盒子 */
box-sizing: border-box;
}
.left-box {
position: relative;
margin-top: 100px;
margin-left: 100px;
width: 400px;
height: 400px;
border: 1px solid #ccc;
}
.left-box>img{
width: 100%;
}
.right-box {
position: absolute;
top: 0;
left: 400px;
width: 500px;
height: 500px;
border: 1px solid #ccc;
/* right-box 下的img不设置宽高,就是显示大图本身大小 800*800 */
/* 父盒子局部显示大图 */
overflow: hidden;
display: none;
}
.right-box>img {
position: absolute;
}
.magnifier-box {
position: absolute;
top: 0;
left: 0;
width: 250px;
height: 250px;
background: rgb(240, 221, 48);
border: 1px dashed rgb(240, 221, 48);
/* 整个盒子的透明度 */
opacity: 0.5;
/* 鼠标样式变成移动的 */
cursor: move;
display: none;
}
// 因为script在DOM之前引入,所以代码要写在onload事件里
// onload:等页面完全加载以后再执行
window.addEventListener('load',function(){
// 左盒子
var left = document.querySelector('.left-box');
// 右盒子
var right = document.querySelector('.right-box');
// 放大镜选区
var magnifier = document.querySelector('.magnifier-box');
// 鼠标经过 显示
left.addEventListener('mouseover',function(){
magnifier.style.display = 'block';
right.style.display = 'block';
})
// 鼠标离开 隐藏
left.addEventListener('mouseout',function(){
magnifier.style.display = 'none';
right.style.display = 'none';
})
// 鼠标移动
left.addEventListener('mousemove',function(event){
// console.dir(left);
// 放大镜选区的移动位置(鼠标在选区左基点)
let magnifierX = event.pageX - left.offsetLeft;
let magnifierY = event.pageY - left.offsetTop;
// 放大镜选区的移动位置(鼠标在选区中间)
let magnifierCenterX = magnifierX - (magnifier.offsetWidth / 2);
let magnifierCenterY = magnifierY - (magnifier.offsetHeight / 2);
// 放大镜选区的最大移动距离,因为是正方形,所以计算一个就行
let magnifierMaxRangeX = left.offsetWidth - magnifier.offsetWidth
// let maxRangeY = left.offsetHeight - magnifier.offsetHeight
// 限制选区移动范围,宽高都要设置
if(magnifierCenterX < 0) {
magnifierCenterX = 0
}
if(magnifierCenterX > magnifierMaxRangeX) {
magnifierCenterX = magnifierMaxRangeX
}
if(magnifierCenterY < 0) {
magnifierCenterY = 0
}
if(magnifierCenterY > magnifierMaxRangeX) {
magnifierCenterY = magnifierMaxRangeX
}
// 放大镜选区的移动
magnifier.style.left = magnifierCenterX + 'px';
magnifier.style.top = magnifierCenterY + 'px';
// 大图
let bigImg = document.querySelector('.bigImg');
// 大图的最大移动距离
let bigImgXMaxRange = bigImg.offsetWidth - right.offsetWidth
// 大图的移动位置
let bigImgX = magnifierCenterX * bigImgXMaxRange / magnifierMaxRangeX
let bigImgY = magnifierCenterY * bigImgXMaxRange / magnifierMaxRangeX
// 大图的移动
bigImg.style.left = -bigImgX + 'px';
bigImg.style.top = -bigImgY + 'px';
})
})