1、使用@vueuser/core包实现
npm i @vueuse/core
2、实现选择小图换大图
代码实现
1、控制大图的src属性为小图列表中的一个
2、编写小图列表
<!-- 大图 -->
<div class="big" ref="target">
<img :src="imglist[currIndex]" alt="">
<!-- 遮罩层 -->
<div class="layout" v-show="!isOutside" :style="{ left: `${left}px`, top: `${top}px` }"></div>
</div>
<!-- 小图 -->
<div class="small">
<div v-for="(item, i) in imglist" :key="i" @mouseenter="changeimg(i)" :class="{ active: i === currIndex }">
<img :src="item" alt="">
</div>
</div>
3、编写小图列表
const imglist = ref([
'https://ts1.cn.mm.bing.net/th/id/R-C.1ca2bda738ff9ce53c690cc0594e1946?rik=LKJAS5fM3DH2mA&riu=http%3a%2f%2fimg.mm4000.com%2ffile%2f0%2f5d%2fbe118211b8.jpg&ehk=2mXSxvTUSTYr3Cvn9KJwXbcnKmAo7T1b5a%2bCTcSRCjo%3d&risl=&pid=ImgRaw&r=0',
'https://ts1.cn.mm.bing.net/th/id/R-C.1f57e1696b81e9b43b3668f326f31aa8?rik=S7FXlry6dGgDcA&riu=http%3a%2f%2fimg.mm4000.com%2ffile%2f3%2f50%2f1893738e93.jpg%3fdown&ehk=Y1ObY1WkhzdSbZn1i4%2fGCSscxBrZvY16e8Jnv7NBjbs%3d&risl=&pid=ImgRaw&r=0',
'https://www.qqkw.com/d/file/p/2018/05-17/0515954b9ce3b4eee4774a73406ed5b6.jpg'
])
4、实现鼠标进入小图,大图展示对应图片
给小图for循环,添加属性,鼠标进入属性,执行changeimg函数,
const currIndex = ref(0)
const changeimg = (i) => {
currIndex.value = i
}
动态绑定选中的样式
:class="{ active: i === currIndex }"
3、放大图展示
引入useMouseInElement属性,用来表示鼠标当前位置(相对与选中的ref)
import { useMouseInElement } from '@vueuse/core'
根据前面的大图div标签的ref="target"属性
// target大图目标
const target = ref(null)
const { elementX, elementY, isOutside } = useMouseInElement(target)
定义遮罩层
<!-- 大图 -->
<div class="big" ref="target">
<img :src="imglist[currIndex]" alt="">
<!-- 遮罩层 -->
<div class="layout" v-show="!isOutside" :style="{ left: `${left}px`, top: `${top}px` }"></div>
</div>
定义left,top属性,用来判断遮罩层的位置
const left = ref(0)
const top = ref(0)
限制遮罩层移动(可移动区域,临界移动区域)
watch([elementX, elementY, isOutside], () => {
if (isOutside.value){
// console.log(target)
// target.style.display='none'
return
}
// 有限移动区间
if (elementX.value > 50 && elementX.value < 150) {
left.value = elementX.value - 50
}
if (elementY.value > 50 && elementX.value < 350) {
top.value = elementY.value - 50
}
// 边界值
if (elementX.value < 50) { left.value = 0 }
if (elementX.value > 150) { left.value = 100 }
if (elementY.value < 50) { top.value = 0 }
if (elementY.value > 350) { top.value = 300 }
positionX.value = -left.value
positionY.value = -top.value
})
可移动区域(图片宽200px,高400px)(遮罩层宽100px,高100px)
当鼠标进入target中,
elementX>50px,elementX<150px,设置left为elementX-遮罩层宽的一半
elementY>50px,elementY<150px,设置top为elementY-遮罩层高的一半
达到鼠标中心在遮罩层中心的效果
临界值区域
elementX<50px,elementX>150px,设置left为0 或 图片的宽-遮罩层的宽
elementY>50px,elementY<150px,设置top为0 或 图片的高-遮罩层的高
遮罩层就不会跑出图片之外了
设置放大后的图,style设置选中的图片,控制展示的位置 backgroundPositionX
<!-- 放大的大图 -->
<div v-show="!isOutside" class="large" :style="[{
backgroundImage: `url(${imglist[currIndex]})`,
backgroundPositionX: `${positionX}px`,
backgroundPositionY: `${positionY}px`
}]">
使用定位让大图在右边
.large {
width: 200px;
height: 400px;
position: absolute;
left: 210px;
top: 7px;
background-color: #ccc;
background-size: 400px 800px;
}
4、完整代码实现
<template>
<!-- 大图 -->
<div class="big" ref="target">
<img :src="imglist[currIndex]" alt="">
<!-- 遮罩层 -->
<div class="layout" v-show="!isOutside" :style="{ left: `${left}px`, top: `${top}px` }"></div>
</div>
<!-- 放大的大图 -->
<div v-show="!isOutside" class="large" :style="[{
backgroundImage: `url(${imglist[currIndex]})`,
backgroundPositionX: `${positionX}px`,
backgroundPositionY: `${positionY}px`
}]">
</div>
<!-- 小图 -->
<div class="small">
<div v-for="(item, i) in imglist" :key="i" @mouseenter="changeimg(i)" :class="{ active: i === currIndex }">
<img :src="item" alt="">
</div>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
import { useMouseInElement } from '@vueuse/core'
const imglist = ref([
'https://ts1.cn.mm.bing.net/th/id/R-C.1ca2bda738ff9ce53c690cc0594e1946?rik=LKJAS5fM3DH2mA&riu=http%3a%2f%2fimg.mm4000.com%2ffile%2f0%2f5d%2fbe118211b8.jpg&ehk=2mXSxvTUSTYr3Cvn9KJwXbcnKmAo7T1b5a%2bCTcSRCjo%3d&risl=&pid=ImgRaw&r=0',
'https://ts1.cn.mm.bing.net/th/id/R-C.1f57e1696b81e9b43b3668f326f31aa8?rik=S7FXlry6dGgDcA&riu=http%3a%2f%2fimg.mm4000.com%2ffile%2f3%2f50%2f1893738e93.jpg%3fdown&ehk=Y1ObY1WkhzdSbZn1i4%2fGCSscxBrZvY16e8Jnv7NBjbs%3d&risl=&pid=ImgRaw&r=0',
'https://www.qqkw.com/d/file/p/2018/05-17/0515954b9ce3b4eee4774a73406ed5b6.jpg'
])
const currIndex = ref(0)
const changeimg = (i) => {
currIndex.value = i
}
// target大图目标
const target = ref(null)
const { elementX, elementY, isOutside } = useMouseInElement(target)
const left = ref(0)
const top = ref(0)
const positionX = ref(0)
const positionY = ref(0)
// 根据xy,改变边界值和临界值
watch([elementX, elementY, isOutside], () => {
if (isOutside.value){
// console.log(target)
// target.style.display='none'
return
}
// 有限移动区间
if (elementX.value > 50 && elementX.value < 150) {
left.value = elementX.value - 50
}
if (elementY.value > 50 && elementX.value < 350) {
top.value = elementY.value - 50
}
// 边界值
if (elementX.value < 50) { left.value = 0 }
if (elementX.value > 150) { left.value = 100 }
if (elementY.value < 50) { top.value = 0 }
if (elementY.value > 350) { top.value = 300 }
positionX.value = -left.value
positionY.value = -top.value
})
</script>
<style scoped lang="less">
.big {
position: relative;
display: inline-block;
width: 200px;
height: 400px;
img {
width: 100%;
height: 100%;
}
.layout {
position: absolute;
opacity: 0.5;
background-color: #999999;
width: 100px;
height: 100px;
}
}
.small {
display: flex;
img {
width: 100px;
height: 200px;
}
}
.large {
width: 200px;
height: 400px;
position: absolute;
left: 210px;
top: 7px;
background-color: #ccc;
background-size: 400px 800px;
}
.active {
border: 1px green solid;
}
</style>