持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情
近期早上看书📖多些,博客的话,更多的在抽一些零碎的时间在弄,现在的这篇也算是有点纪念意义啦,因为莎童鞋就在我身边玩手机,而我在写博客,哈哈哈哈哈...生活有时候就是这样吧,简单又美好~
开发过程中需要封装一个类似某宝或者某东商品详情页里面,鼠标经过图片,对图片上的区域进行一个放大展示组件,所以就分析了下整个封装的过程吧,也为了以后封装少走弯路。
需要考虑的信息:
-
既然是组件,那么原图片的大小一定是可以通过
props配置的(笔者这里只是将其提取到data的drawEnlargeStyle),用来设置组件展示区原图区域的大小 -
鼠标经过图片,需要有一个跟随鼠标滑动的滑块,来指示要
放大的区域 -
需要一个等大图层用于测量图片移动的位置以及边界问题。
-
在生命周期
created阶段对组件容易的原图大小、原图容器大小、橘红色移动滑块大小、右侧展示区域的图片大小的尺寸进行一个设置。(这里也是可以通过props)进行设置哒,笔者这里暂时放到data中设置,有需要的可以抽取 到props中去进行设置 -
对和图片等大的
蒙层(即 class="maskTop"的div)绑定三个事件进行监听:enterHandler:展示右侧图片以及橘红色移动滑块moveHandler:鼠标移动至原图区域的计算:-
层罩的左上角坐标位置,并对其进行限制:无法超出原图区域左上角
-
对层罩位置再一次限制,保证层罩只能在原图区域空间内
-
这里需要注意的一个点,就是理解放大倍数和右侧展示图片放大的关系:
-
右侧展示图片其实大小是左侧原图的
enlargeTimes倍,之所以有放大效果,是以为他在一定的可视区域内,展示出来图片的冰山一角,给人呈现以放大的感觉。 -
理解了上面👆🏻的点,也就可以理解,右侧图片移动的
transform相应倍数的topX和topY位置
完成效果如下:
最后,组件代码如下:
<!--拍卖详情页-放大器效果-->
<template>
<div class="draw-enlarge" :style="drawEnlargeStyle">
<!-- 图片容器 -->
<div class="left">
<!-- 原图图片 -->
<img class="leftImg" :src="require(`../../assets/images/index/${currImgName}.png`)" alt="" />
<!-- 在原图上移动的罩层 -->
<div v-show="topShow" class="top" :style="topStyle"></div>
<!-- 跟原图等大的罩层 -->
<div
class="maskTop"
@mouseenter="enterHandler"
@mousemove="moveHandler"
@mouseout="outHandler"
></div>
</div>
<!-- 右侧展示放大后的图片 -->
<div v-show="rShow" class="right" :style="rightStyle">
<img
:style="r_img"
class="rightImg"
:src="require(`../../assets/images/index/${currImgName}.png`)"
alt="放大的展示图片"
/>
</div>
</div>
</template>
<script>
export default {
data() {
return {
topStyle: { transform: '' }, //图片上橘红色移动层的样式
drawEnlargeStyle: {}, //组件的样式
r_img: {}, //右侧容器内图片样式
rightStyle: {}, // 右侧容易的样式
topShow: false, // 是否显示图片上移动的的橘红色罩层
rShow: false, // 是否显示右侧图片容器
imgSize: { //图片初始大小
width: 400,
height: 280,
},
shadeSize: { //图片上移动的橘红色移动图层大小
width: 150,
height: 100,
},
magnificationFactor: 3, // 放大倍数
currImgName:'baner1', // 当前展示图片的名称
};
},
props:{
// 图片名称
imgName:{
default:'baner1',
type:String
},
// 放大倍数
enlargeTimes:{
default:3,
type:Number
}
},
watch:{
// 图片名称
imgName:{
handler(newVal,oldVal){
if(newVal !== undefined){
this.currImgName = newVal;
}
},
immediate:true
},
// 放大倍数
enlargeTimes:{
handler(newVal,oldVal){
if(newVal !== undefined){
this.magnificationFactor = newVal;
}
},
immediate:true
}
},
created: function() {
// 设置右侧图片大小
this.$set(this, 'r_img', {
width: this.imgSize.width * this.magnificationFactor + 'px',
height: this.imgSize.height * this.magnificationFactor + 'px',
});
// 设置组件容器展示大小
this.$set(this, 'drawEnlargeStyle', {
width: this.imgSize.width + 'px',
height: this.imgSize.height + 'px',
});
// 设置图片上移动的悬浮层的大小
this.$set(this, 'topStyle', {
width: this.shadeSize.width + 'px',
height: this.shadeSize.height + 'px',
transform: '',
});
// 右侧展示图片容器大小
this.$set(this, 'rightStyle', {
'margin-left': this.imgSize.width + 12 + 'px',
width: this.shadeSize.width * this.magnificationFactor + 'px',
height: this.shadeSize.height * this.magnificationFactor + 'px',
});
},
methods: {
/**
* @function 鼠标移入处理
*/
enterHandler() {
this.topShow = true;
this.rShow = true;
},
/**
* @function 鼠标在原图中移动的处理
*/
moveHandler(event) {
let x = event.offsetX;
let y = event.offsetY;
// 层罩的左上角坐标位置,并对其进行限制:无法超出原图区域左上角
let topX =
x - this.shadeSize.width / 2 < 0 ? 0 : x - this.shadeSize.width / 2;
let topY =
y - this.shadeSize.height / 2 < 0 ? 0 : y - this.shadeSize.height / 2;
// 对层罩位置再一次限制,保证层罩只能在原图区域空间内
if (topX > this.imgSize.width - this.shadeSize.width) {
topX = this.imgSize.width - this.shadeSize.width;
}
if (topY > this.imgSize.height - this.shadeSize.height) {
topY = this.imgSize.height - this.shadeSize.height;
}
// 通过 transform 进行移动控制
this.topStyle.transform = `translate(${topX}px,${topY}px)`;
this.r_img.transform = `translate(-${this.magnificationFactor *
topX}px,-${this.magnificationFactor * topY}px)`;
},
/**
* @function 鼠标移除后的功能处理
*/
outHandler() {
// 控制层罩与放大空间的隐藏
this.topShow = false;
this.rShow = false;
},
},
};
</script>
下面为css部分的代码:
//css 部分
<style scoped>
.draw-enlarge {
position: relative;
}
/* 放大的图片,通过定位将左上角定位到(0,0) */
.draw-enlarge .rightImg {
display: inline-block;
position: absolute;
top: 0;
left: 0;
}
/* 右边的区域图片放大空间 */
.draw-enlarge .right {
width: 100%;
height: 100%;
position: absolute;
overflow: hidden;
z-index: 999;
}
/* 一个最高层层罩 */
.draw-enlarge .maskTop {
width: 100%;
height: 100%;
position: absolute;
z-index: 1;
top: 0;
left: 0;
}
/* 层罩,通过定位将左上角定位到(0,0) */
.draw-enlarge .top {
background-color: lightcoral;
opacity: 0.4;
position: absolute;
top: 0;
left: 0;
}
/* 原图的显示 */
.draw-enlarge .leftImg {
width: 100%;
height: 100%;
display: inline-block;
}
/* 原图的容器 */
.draw-enlarge .left {
width: 100%;
height: 100%;
float: left;
position: relative;
}
</style>