图片通过滑块小图切换大图放大镜效果显示
图片通过滑块小图切换大图放大镜效果显示
实现目标:
-
显示一组图片列表,鼠标进入小图记录当下小图下标,通过小图下标在数组中对应图片显示到大图位置;
-
鼠标进入大图位置时,带动滑块移动,并将放大两倍的大图显示在原大图右边
实现过程:
- 实现小图切换大图:通过v-for将图片列表绑定在li标签上,同时为li标签添加鼠标监测事件,并绑定事件处理函数
enterHandler
,传入图片索引 i 。初始化响应数据activeIndex
记录当前激活索引。通过v-on
加强 li 标签的样式 ,active
激活条件为i=== activeIndex
即当前激活索引与小图索引相同时,左侧大图链接为激活图片索引imageList[sctiveIndex]
。 - 导入VueUse的
useMouseInElement
元素获取鼠标位置,记录鼠标相对位置elementX、elementY
,初始化放大图坐标positionX、positionY
,通过监听器watch
监听鼠标相对位置的变化,小滑块通过left 、 top
控制位置
图中红色正方形为滑块位置,蓝色正方形内为滑块控制的有效范围,需要处理边界(黑色正方形与蓝色正方形的差集)
控制滑块移动:
// 横向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 < 100) {left.value = 0}if (elementX.value > 300) {left.value = 200}if (elementY.value < 100) {top.value = 0}if (elementY.value > 300) {top.value = 200}
- 控制放大图显示
注意观察,当鼠标在左侧大图移动时,右侧放大图移动方向相反
控制放大图坐标:
// 控制大图显示positionX.value = -left.value * 2positionY.value = -top.value * 2// 控制放大图图片样式
<divclass="large":style="[{backgroundImage: `url(${imageList[activeIndex]})`,backgroundPositionX: `${positionX}px`,backgroundPositionY: `${positionY}px`,},]"v-show="!isOutside"></div>
【注:图片源自淘宝,如有侵权立刻删除】
完整代码
<script setup>
import { useMouseInElement } from '@vueuse/core'
import { ref, watch } from 'vue'// 图片列表
const imageList = ['img/O1CN01HhRDRN1PLRFptsiNY_!!2210715771824.jpg_.webp','img/O1CN01TgHapK1PLRFzgigEa_!!2210715771824.jpg_.webp','img/O1CN015Lpahn1PLRFzgiLRv_!!2210715771824.jpg_.webp','img/O1CN017pJsbA1PLRG0Uk1UI_!!2210715771824.jpg_ (1).webp','img/O1CN017pJsbA1PLRG0Uk1UI_!!2210715771824.jpg_.webp',
]// 小图切换大图
const activeIndex = ref(0)
const enterHandler = (i) => {activeIndex.value = i
}// 获取鼠标相对位置
const target = ref(null)
const { elementX, elementY, isOutside } = useMouseInElement(target)// 控制滑块跟随鼠标移动(监听XY变化,变化则重新设计left/top)
const left = ref(0)
const top = ref(0)const positionX = ref(0)
const positionY = ref(0)
watch([elementX, elementY, isOutside], () => {if (isOutside.value) {return}// 有效范围内控制滑块距离// 横向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 < 100) {left.value = 0}if (elementX.value > 300) {left.value = 200}if (elementY.value < 100) {top.value = 0}if (elementY.value > 300) {top.value = 200}// 控制大图显示positionX.value = -left.value * 2positionY.value = -top.value * 2
})
</script><template><div class="goods-image"><!-- 左侧大图--><div class="middle" ref="target"><img :src="imageList[activeIndex]" alt="" /><!-- 蒙层小滑块 --><div class="layer" :style="{ left: `${left}px`, top: `${top}px` }"></div></div><!-- 小图列表 --><ul class="small"><liv-for="(img, i) in imageList":key="i"@mouseenter="enterHandler(i)":class="{ active: i === activeIndex }"><img :src="img" alt="" /></li></ul><!-- 放大镜大图 --><divclass="large":style="[{backgroundImage: `url(${imageList[activeIndex]})`,backgroundPositionX: `${positionX}px`,backgroundPositionY: `${positionY}px`,},]"v-show="!isOutside"></div></div>
</template><style scoped lang="scss">
.goods-image {width: 480px;height: 400px;position: relative;display: flex;.middle {width: 400px;height: 400px;background: #f5f5f5;}img {max-width: 100%;max-height: 100%;}.large {position: absolute;top: 0;left: 412px;width: 400px;height: 400px;z-index: 500;box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);background-repeat: no-repeat;// 背景图:盒子的大小 = 2:1 控制背景图的移动实现放大的效果background-size: 800px 800px;background-color: #f8f8f8;}.layer {width: 200px;height: 200px;background: rgba(0, 0, 0, 0.2);// 绝对定位left: 0;top: 0;position: absolute;}.small {width: 80px;list-style: none;li {width: 68px;height: 68px;margin-left: 12px;margin-bottom: 15px;cursor: pointer;&:hover,&.active {border: 2px solid pink;}}}
}
* {box-sizing: border-box;
}
</style>