记录一下最近做的一个小功能,放大镜效果实现。 首先准备一个静态页面,包含以下模块:
<div class="middle" ref="target">
<img :src="imageList[0]" alt="" />
<!-- 蒙层小滑块 -->
<div class="layer" :style="{ left: `0px`, top: `0px` }"></div>
</div>
<!-- 小图列表 -->
<ul class="small">
<li v-for="(img, i) in imageList" :key="i">
<img :src="img" alt="" />
</li>
</ul>
<!-- 放大镜大图 -->
<div class="large" :style="[
{
backgroundImage: `url(${imageList[0]})`,
backgroundPositionX: `0px`,
backgroundPositionY: `0px`,
},
]" v-show="false"></div>
</div>
得到的静态页面如下:
接着就开始写交互逻辑:
- 第一步先去写一个鼠标进入右侧小图,使得右侧小图边框提示变绿的效果。
//逻辑:1.通过v-for获取鼠标进入的标签序号,然后保存序号,再动态加class
<!-- 小图列表 -->
<script setup>
let curIdx = ref(0)
</script>
<ul class="small">
<li v-for="(img, i) in imageList" :key="i" @mouseenter="curIdx = i" :class="{ active: curIdx === i }">
<img :src="img" alt="" />
</li>
</ul>
- 第二步将左侧大图的img标签的src动态绑定成右侧激活的小图src地址
<!-- 左侧大图-->
<div class="middle" ref="target">
<img :src="imageList[curIdx]" alt="" />
<!-- 蒙层小滑块 -->
<div class="layer" :style="{ left: `${layer_x}px`, top: `${layer_y}px` }"></div>
</div>
- 获取鼠标位置,在这里我使用的是vueUse的APIuseMouseInElement,结构该方法返回的值,得到需要的三个值x, y, isOutside。然后控制蒙层小滑块随着鼠标移动,
<script setup>
// 2. 获取鼠标相对位置
const target = ref(null)
const { elementX, elementY, isOutside } = useMouseInElement(target)
// 3. 控制滑块跟随鼠标移动(监听elementX/Y变化,一旦变化 重新设置left/top)
const left = ref(0)
const top = ref(0)
const positionX = ref(0)
const positionY = ref(0)
watch([elementX, elementY, isOutside], () => {
console.log('xy变化了')
// 如果鼠标没有移入到盒子里面 直接不执行后面的逻辑
if (isOutside.value) return
console.log('后续逻辑执行了')
// 有效范围内控制滑块距离
// 横向
if (elementX.value > 100 && elementX.value < 300) {
left.value = elementX.value - 100
}
// 纵向
if (elementY.value > 100 && elementY.value < 300) {
top.value = elementY.value - 100
}
// 处理边界
if (elementX.value > 300) { left.value = 200 }
if (elementX.value < 100) { left.value = 0 }
if (elementY.value > 300) { top.value = 200 }
if (elementY.value < 100) { top.value = 0 }
// 控制大图的显示
positionX.value = -left.value * 2
positionY.value = -top.value * 2
})
</script>
<!-- 蒙层小滑块 -->
<div class="layer" v-show="!isOutside" :style="{ left: `${left}px`, top: `${top}px` }"></div>
4.实现放大镜逻辑,实际就是用一个两倍于左侧大图的div标签装放大镜的图,将背景图设置成左侧大图的url,然后用backgroundPositionX/Y来控制放大镜的显示。
<script setup>
// 控制大图的显示
positionX.value = -left.value * 2
positionY.value = -top.value * 2
</script>
<!-- 放大镜大图 -->
<div class="large" :style="[
{
backgroundImage: `url(${imageList[0]})`,
backgroundPositionX: `${positionX}px`,
backgroundPositionY: `${positionY}px`,
},
]" v-show="!isOutside"></div>
</div>