昨天在做商品详情页面时,遇到一个需求,就是图片放大镜效果。在图片上鼠标划过时,右侧出现一个大图,用于展示鼠标移过的区域,也就是图片放大镜效果。
效果图基本类似如下:
我之前有篇文章js实现图片放大镜效果:https://blog.csdn.net/yehaocheng520/article/details/115278622?spm=1001.2014.3001.5501
当时是用js
实现的效果,因此现在要把代码嫁接到vue
创建的项目中。
html
部分代码:
<div class="big-img-box" ref="big-img-box" @mouseleave="moveend">
<div class="imgWrap" @mouseenter="movestart" @mousemove.stop>
<img :src="HOST + commonUploadFileUrl + bigImgsrc" alt="" />
</div>
<div
v-if="bigImgUrl"
@mousemove.stop
@mousemove="move"
class="move"
ref="move"
:style="{ left: -left / 3 + 'px ', top: -top / 3 + 'px' }"
></div>
<div
class="bigPic"
ref="bigPic"
v-if="bigImgUrl"
:style="{ backgroundPosition: left + 'px ' + top + 'px' }"
></div>
</div>
<div class="small-img-box">
<div class="img-content-box">
<ul>
<li
v-for="(item, index) in detailInfo.images"
:key="index"
@mouseover="handleBigImg(item, index)"
:class="{ smallImgBorder: currentSmallImgIndex == index }"
>
<img :src="HOST + commonUploadFileUrl + item.src" alt="" />
</li>
</ul>
</div>
</div>
图片放大镜效果的重点——css
和js
部分
css
部分的关键
这个效果有个特别的css
样式,分析一下有几个元素;
左侧图片原图:这个就是个普通的图片,可以通过background
设置图片路径,也可以是一个img
标签来展示。
图片上的鼠标移动区域:这个比较需要注意的是:这个是个绝对布局,为了js
部分计算简单,我使用了200x200
的大小,颜色为一个偏透明的色号
右侧大图:这个也是个绝对布局,采用background
的方式来设置图片路径和背景参数,background-size
设置成大于1的参数。
css
部分代码如下:
.big-img-box {
width: 480px;
height: 360px;
margin: 0 0 20px;
border: 1px solid #eee;
position: relative;
.imgWrap {
width: 100%;
height: 100%;
overflow: hidden;
}
.move {
position: absolute;
left: 0;
top: 0;
width: 200px;
height: 200px;
background: rgba(0, 0, 255, 0.15);
cursor: move;
}
.bigPic {
width: 480px;
height: 480px;
position: absolute;
left: 480px;
top: 0;
border: 2px solid #f90;
background-position: 0 0;
background-size: 300% 300%;
background-repeat: no-repeat;
z-index: 2;
}
}
原图下方的小图部分:就是一排普通的图片,css
样式部分并无不同
.small-img-box {
width: 480px;
height: 70px;
position: relative;
.img-content-box {
width: 100%;
margin: 0 auto;
height: 100%;
display: block;
ul {
width: 105%;
height: 100%;
li {
display: inline-block;
width: 88px;
height: 100%;
margin-right: 10px;
overflow: hidden;
img {
display: block;
width: 100%;
}
}
}
}
}
js
部分的关键——鼠标的移入移出事件+dom
元素的位置及大小
在用js
实现此效果时,需要用到几个重要的参数
- 左侧原图距离左侧的大小——
oAppLeft
- 左侧原图距离上方的大小——
oAppTop
- 鼠标移入后的位置
e.pageX e.pageY
,之前的js
版本的效果用的是e.clientX e.clientY
,这个e.clientX
有问题,这个参数会跟着屏幕的滚动而发生变化,我们需要的是一个不会变化的值,鼠标的位置对于整个页面来说是固定的,而不是随着页面的滚动发生变化。 - 移动区域的大小——可以通过
style.width style.height
来获取,但是我在css
部分为了方便,直接固定为200X200
,因此我这边是直接使用的200
的数值
左侧原图距离左边和上边的大小——oAppLeft
与oAppTop
的计算
mounted() {
this.$nextTick(() => {//页面加载完成后再去获取`dom`元素的位置
this.oAppLeft = this.$refs["big-img-box"].offsetLeft;
this.oAppTop = this.$refs["big-img-box"].offsetTop;
});
},
针对普通的dom
元素可以通过this.$refs[xxx].xxx
的方式来获取
针对v-for
等渲染的dom
元素可以通过this.$refs[xxx][0].xxx
的方式来获取
鼠标移入移出需要注意的部分:
- 左侧原图具体展示哪张图片可以根据一个字段
bigImgUrl
来处理。下方下图鼠标移入时,更改bigImgUrl
的值,就可以了 - 鼠标移入到左侧原图时,开始出现选择框,右侧展示选择框中的图片放大效果,也就是说:左侧原图需要加一个鼠标移入的监听事件
<div class="big-img-box" ref="big-img-box" @mouseleave="moveend">
<div class="imgWrap" @mouseenter="movestart" @mousemove.stop>
<img :src="HOST + commonUploadFileUrl + bigImgsrc" alt="" />
</div>
<div v-if="bigImgUrl" @mousemove.stop @mousemove="move" class="move" ref="move"
:style="{ left: -left / 3 + 'px ', top: -top / 3 + 'px' }"></div>
<div class="bigPic" ref="bigPic" v-if="bigImgUrl" :style="{ backgroundPosition: left + 'px ' + top + 'px' }"> </div>
</div>
上面html
结构中的class='imgWrap'就是左侧原图部分
;
鼠标移入的函数——鼠标移入的位置就是选择框的初始位置
//鼠标移入后,就要展示选择框,因此鼠标移入的位置跟选择框的位置有关
movestart(e) {
this.move(e);
this.bigImgUrl = this.bigImgsrc;
var imgUrl = this.HOST + this.commonUploadFileUrl + this.bigImgUrl;//这个就是当前图片的路径,不管多管
this.$nextTick(() => {//页面加载完成后,更改大图的`backgroundImage`,这个也可以直接在html中动态绑定style,那样会简单很多
this.$refs.bigPic.style.backgroundImage = `url(${imgUrl})`;
});
},
选择框鼠标移动的位置——改变选择框的位置
//鼠标移动时,选择框的位置也会发现改变
move(e) {
var left = e.pageX - this.oAppLeft - 100;
var top = e.pageY - this.oAppTop - 100;
if (left < 0) {
left = 0;
} else if (left > 280) {
left = 280;
}
if (top < 0) {
top = 0;
} else if (top > 160) {
top = 160;
}
this.left = -left * 3;
this.top = -top * 3;
},
左侧原图鼠标移出——隐藏选择框和大图(将bigImgUrl
置为空即可)
moveend() {
this.bigImgUrl = "";
this.left = 0;
this.top = 0;
},
最终功能实现!!!!
补充:注意事项——上面的比例部分有问题,更改如下:
1.左侧原图最好是设置为div
的背景图片
<div class="imgWrap" @mouseenter="movestart" @mousemove.stop :style="{backgroundImage: `url(${HOST + commonUploadFileUrl + bigImgsrc})`}">
因为图片放大镜的原理就是通过backgroundSize
+backgroundPostion
两个属性配合使用的。为了保证左侧原图和右侧大图保持一致。最好统一都设置为背景图片。如果左侧原图不设置为背景图片,则需要将class="imgWrap"
中的img
宽高设置为100%.
2.比例是怎么来的?
在这个项目中,有用到两个比例,一个是右侧大图backgroundSize
,一个是右侧大图的位置left top
的计算比例。
注意此处的background-size
的比例跟左侧原图的宽高是有关系的。
左侧原图的宽高比例是:480:360,也就是:4:3;因此右侧大图的background-size
应该设置为400% 300%
;上面的比例是错误的。或者可以将左侧原图的大小改为:width:360px;height:360px;
,则此时的右侧大图的background-size
可以设置为300% 300%
,也就是方法3倍的意思。
this.left this.top
的比例是怎么来的????
注意这个地方:左侧原图上的选择框大小是:width:200px height:200px
,右侧大图的大小是:width:360px; height:360px;
,也就是右侧大图是左侧选择框的1.8倍,因此此处的比例应该是1.8
,上面的内容应该改为:this.left = -left * 1.8;this.top = -top*1.8;
选择框在左侧原图中的边界计算:
一定要注意:我们计算的是选择框的left top
值,也就是左上角顶点的位置。
因此选择框的边界4个值就是:(0,0) (左侧原图的宽度-选择框的宽度,0) (左侧原图的宽度-选择框的宽度,左侧原图的高度-选择框的高度) (0,左侧原图的高度-选择框的高度)