【JavaScript】网页放大镜效果案例
- 加深对e.pageX,e.pageY,offsetLeft,offsetTop,offsetWidth,offsetHeight的理解和应用
- 鼠标事件mouseover,mouseout,mousemove的应用
实现效果: 鼠标在左侧小图中移动,右侧对应显示该部分区域放大效果。
实现效果预览:
首先搭建一个简单的网页结构:
<style>
* {
margin: 0;
padding: 0;
}
.wrap {
width: 1200px;
margin: 50px auto;
background-color: #ccc;
overflow: hidden;
}
.left {
float: left;
width: 400px;
}
.right {
float: left;
width: 800px;
height: 800px;
background-color: antiquewhite;
}
.preview-img {
height: 400px;
border: 1px solid #ccc;
box-sizing: border-box;
position: relative;
cursor: move;
}
.mask {
position: absolute;
left: 0;
top: 0;
width: 300px;
height: 300px;
background-color: #FEDE4F;
opacity: 0.5;
/*display: none;*/
}
.big {
position: absolute;
top: 0;
left: 101%;
width: 500px;
height: 500px;
border: 1px solid #ccc;
box-sizing: border-box;
background-color: pink;
overflow: hidden;
/*display: none;*/
}
</style>
<body>
<div class="wrap">
<div class="left">
<div class="preview-img">
<img src="images/small.png" alt="">
<div class="mask"></div>
<div class="big">
<img src="images/big.jpg" alt="" id="bigImg">
</div>
</div>
<div>2222</div>
</div>
<div class="right">
3333
</div>
</div>
</body>
效果如下:
一、首先实现:鼠标经过 preview_img时,就显示 mask 遮挡层 和 big 大盒子的效果,鼠标离开时,就隐藏。
这个较为简单,首先让mask 遮挡层 和 big 大盒子隐藏起来,然后通过mouseover和mouseout函数实现。
代码如下:
- 首先让mask 遮挡层 和 big 大盒子隐藏起来。
<style>
.mask {
position: absolute;
left: 0;
top: 0;
width: 300px;
height: 300px;
background-color: #FEDE4F;
opacity: 0.5;
display: none;
}
.big {
position: absolute;
top: 0;
left: 101%;
width: 500px;
height: 500px;
border: 1px solid #ccc;
box-sizing: border-box;
background-color: pink;
overflow: hidden;
display: none;
}
</style>
- 给previewImg绑定鼠标经过和鼠标离开事件。
var mask = document.querySelector('.mask');
var big = document.querySelector('.big');
var previewImg = document.querySelector('.preview-img');
var bigImg = document.getElementById('bigImg');
//鼠标经过显示
previewImg.addEventListener('mouseover', function () {
mask.style.display = 'block';
big.style.display = 'block';
})
//鼠标离开隐藏
previewImg.addEventListener('mouseout', function () {
mask.style.display = 'none';
big.style.display = 'none';
})
效果如下:
二、实现:mask跟着鼠标移动。因为鼠标是在previewImg里面移动,所以是给previewImg绑定mousemove事件。
- 计算鼠标在previewImg盒子中的坐标。
previewImg往上找有定位的父元素,没有找到(.left和.wrap都没有设置定位)。因此previewImg.offsetLeft就是previewImg盒子距离整个页面左侧的距离。
因此,鼠标在previewImg盒子中的x坐标就是:鼠标距离整个页面左侧的距离-previewImg盒子距离整个页面左侧的距离,也就是e.pageX - previewImg.offsetLeft,y坐标同理。 - 给mask设置left,top值,就能实现鼠标跟随移动效果。
mask的父级previewImg有定位,所以鼠标在previewImg盒子中的x坐标就是mask应该距离父级左边的距离,直接让left值等于maskX即可,注意加‘px’。
代码如下:
previewImg.addEventListener('mousemove', function (e) {
//1.计算鼠标在previewImg中的坐标
var maskX = e.pageX - this.offsetLeft;
var maskY = e.pageY - this.offsetTop;
//2.mask跟随鼠标移动
//给mask设置left,top值,注意mask的父级previewImg有定位,所以maskX就是mask应该距离父级左边的距离
mask.style.left = maskX + 'px';
mask.style.top = maskY + 'px';
})
- 此时已实现跟随效果,但是鼠标总是位于mask盒子的左上角,我们稍微改进一下,让鼠标在mask盒子的中心显示。
在赋值left值之前,首先减去mask盒子一半宽度。top值同理。
代码如下:
previewImg.addEventListener('mousemove', function (e) {
//1.计算鼠标在mask中的坐标
var maskX = e.pageX - this.offsetLeft;
var maskY = e.pageY - this.offsetTop;
//2.mask跟随鼠标移动
//(1)让鼠标在mask的中心显示
maskX = maskX - mask.offsetWidth / 2;
maskY = maskY - mask.offsetHeight / 2;
//(2)给mask设置left,top值,注意mask的父级previewImg有定位,所以maskX就是mask应该距离父级左边的距离
mask.style.left = maskX + 'px';
mask.style.top = maskY + 'px';
})
此时的效果是这样的:
可以看出,是存在问题的,mask会超出previewImg的范围。而mask应该在previewImg里面移动,不能超出previewImg的范围。所以我们需要限定一下mask的范围。
- 给mask限定边界。mask在x.y轴上的最小移动距离就是0,分别计算出mask在x.y轴上的最大移动距离,x轴最大移动距离就是previewImg的宽度-mask的宽度。y轴同理。
代码如下:
previewImg.addEventListener('mousemove', function (e) {
//1.计算鼠标在mask中的坐标
var maskX = e.pageX - this.offsetLeft;
var maskY = e.pageY - this.offsetTop;
//2.mask跟随鼠标移动
//(1)让鼠标在mask的中心显示
maskX = maskX - mask.offsetWidth / 2;
maskY = maskY - mask.offsetHeight / 2;
//(2)给mask限定边界
var maxMoveX = this.offsetWidth - mask.offsetWidth;
var maxMoveY = this.offsetHeight - mask.offsetHeight;
if (maskX < 0) {
maskX = 0;
} else if (maskX > maxMoveX) {
maskX = maxMoveX;
}
if (maskY < 0) {
maskY = 0;
} else if (maskY > maxMoveY) {
maskY = maxMoveY;
}
//(3)给mask设置left,top值,注意mask的父级previewImg有定位,所以maskX就是mask应该距离父级左边的距离
mask.style.left = maskX + 'px';
mask.style.top = maskY + 'px';
})
效果如下:
三、实现:右边对应显示大图。
- 这是一个数学问题,首先我们整理一下左右两边图层的关系。
previewImg(也就是small.png)对应#bigImg,都是下面那张大的底图。mask对应的是.big,可以认为他们都是盖在底图上的一个小一些的显示窗口。 - 计算大图对应应该移动多少像素 比例关系。
小窗口在小图上移动多少与大窗口在大图上移动距离应该是成比例的,才能显示相同的区域。
所以x=maskX * bigImg.offsetWidth / previewImg.offsetWidth,y同理。 - 给bigImg设置left,top值(还是添加在previewImg的mousemove事件里)。
(1)注意这里大图是是移动底图bigImg,而上面小图是移动窗口mask,所以方向是反的,取负值。
(2)而bigImg没有定位,所以没有left,top值,还要记得返回去给它添加定位。
代码如下:
<style>
#bigImg {
position: absolute;
top: 0;
left: 0;
}
</style>
//3.对应显示大图
//(1)计算大图对应应该移动多少像素 比例关系
var bigX = maskX * bigImg.offsetWidth / this.offsetWidth;
var bigY = maskY * bigImg.offsetHeight / this.offsetHeight;
//(2)给bigImg设置left,top值。
bigImg.style.left = -bigX + 'px';
bigImg.style.top = -bigY + 'px';
效果如下:
附上完整代码:
<style>
* {
margin: 0;
padding: 0;
}
.wrap {
width: 1200px;
margin: 50px auto;
background-color: #ccc;
overflow: hidden;
}
.left {
float: left;
width: 400px;
/* background-color: pink; */
}
.right {
float: left;
width: 800px;
height: 800px;
background-color: antiquewhite;
}
.preview-img {
height: 400px;
border: 1px solid #ccc;
box-sizing: border-box;
position: relative;
cursor: move;
}
.mask {
position: absolute;
left: 0;
top: 0;
width: 300px;
height: 300px;
background-color: #FEDE4F;
opacity: 0.5;
display: none;
}
.big {
position: absolute;
top: 0;
left: 101%;
width: 500px;
height: 500px;
border: 1px solid #ccc;
box-sizing: border-box;
background-color: pink;
overflow: hidden;
display: none;
}
#bigImg {
position: absolute;
top: 0;
left: 0;
}
</style>
<body>
<div class="wrap">
<div class="left">
<div class="preview-img">
<img src="images/small.png" alt="">
<div class="mask"></div>
<div class="big">
<img src="images/big.jpg" alt="" id="bigImg">
</div>
</div>
<div>2222</div>
</div>
<div class="right">
3333
</div>
</div>
<script>
var mask = document.querySelector('.mask');
var big = document.querySelector('.big');
var previewImg = document.querySelector('.preview-img');
var bigImg = document.getElementById('bigImg');
//鼠标经过显示
previewImg.addEventListener('mouseover', function () {
mask.style.display = 'block';
big.style.display = 'block';
})
previewImg.addEventListener('mouseout', function () {
mask.style.display = 'none';
big.style.display = 'none';
})
//mask跟着鼠标移动
previewImg.addEventListener('mousemove', function (e) {
//1.计算鼠标在mask中的坐标
var maskX = e.pageX - this.offsetLeft;
var maskY = e.pageY - this.offsetTop;
//2.mask跟随鼠标移动
//(1)让鼠标在mask的中心显示
maskX = maskX - mask.offsetWidth / 2;
maskY = maskY - mask.offsetHeight / 2;
//(2)给mask限定边界
var maxMoveX = this.offsetWidth - mask.offsetWidth;
var maxMoveY = this.offsetHeight - mask.offsetHeight;
if (maskX < 0) {
maskX = 0;
} else if (maskX > maxMoveX) {
maskX = maxMoveX;
}
if (maskY < 0) {
maskY = 0;
} else if (maskY > maxMoveY) {
maskY = maxMoveY;
}
//(3)给mask设置left,top值。
mask.style.left = maskX + 'px';
mask.style.top = maskY + 'px';
//3.对应显示大图
//(1)计算大图对应应该移动多少像素 比例关系
var bigX = maskX * bigImg.offsetWidth / this.offsetWidth;
var bigY = maskY * bigImg.offsetHeight / this.offsetHeight;
//(2)给bigImg设置left,top值。
bigImg.style.left = -bigX + 'px';
bigImg.style.top = -bigY + 'px';
})
</script>
</body>
代码到最后都可以归结为数学问题。学好数学的重要性hhh