记录一下写代码的过程,主要就是控制滑块,滑块移动的地方会在右侧试图区放大,使用这个组件时需要把需要放大的图片传入,并且允许自定义图片区尺寸,滑块的样式和放大视图区的尺寸和位置,放大的原理是css的scale属性,读取滑块的移动位置,把滑块的位置图片的放大在右侧,并且跟随滑块移动而移动,注意右侧放大的图片移动方向是和滑块移动方向相反的
<script setup>
<template>
<div class="imgBox" ref="imgbox">
<slot></slot>
<div class="mask"
v-show="state.isShow"
:style="{
left:state.maskX + 'px',
top :state.maskY +'px'}">
</div>
</div>
<transition name="fade">
<div class="zoomBox"
v-show="state.isShow"
:style="{left :state.boxX +'px',top: state.boxY +'px',}">
<img :src="state.imgSrc"
:style="{
width:state.zoomImgWidth + 'px',
height: state.zoomImgHeight + 'px',
marginLeft :-state.bImgX + 'px',
marginTop : -state.bImgY + 'px'
}">
</div>
</transition>
</template>
<script setup>
import {defineProps, onMounted, onUnmounted, reactive, ref} from 'vue'
const maskWidth = 50,
maskHeight = 50
const imgbox = ref(null)
const props = defineProps({mode: String})
const state = reactive({
zoomImgWidth: 0,
zoomImgHeight: 0,
isShow: false,
boxX: 0,
boxY: 0,
maskX: 0,
maskY: 0,
bImgX: 0,
bImgY: 0,
imgSrc: ''
})
const zommIn = (ev) => {
const img = ev.currentTarget.getElementsByTagName('img')[0]
const {offsetWidth, offsetTop, offsetHeight} = imgbox.value
state.zoomImgWidth = offsetWidth * 3
state.zoomImgHeight = offsetHeight * 3
state.imgSrc = img.src
state.boxX = offsetWidth
state.boxY = offsetTop
state.isShow = true
}
const zoomMove = (ev) => {
const {clientX, clientY} = ev
const {offsetTop, offsetLeft} = ev.currentTarget
const {offsetWidth, offsetHeight} = imgbox.value
let mx = clientX - offsetLeft - (maskWidth / 2),
my = clientY - offsetTop - (maskHeight / 2)
mx = mx < 0 ? 0 : mx
my = my < 0 ? 0 : my
if (mx > offsetWidth - maskWidth / 2) {
mx = offsetWidth - maskWidth / 2
}
if (my > offsetHeight - maskHeight / 2) {
my = offsetHeight - maskHeight / 2
}
state.maskX = mx
state.maskY = my
state.bImgX = mx * (state.zoomImgWidth - offsetWidth) / (offsetWidth - maskWidth)
state.bImgY = my * (state.zoomImgWidth - offsetWidth) / (offsetWidth - maskWidth)
}
const zommOut = () => {
state.isShow = false
}
//绑定方法
onMounted(() => {
imgbox.value.addEventListener('mouseover', zommIn)
imgbox.value.addEventListener('mousemove', zoomMove)
imgbox.value.addEventListener('mouseout', zommOut)
})
onUnmounted(() => {
imgbox.value.removeEventListener('mouseover', ()=>{})
imgbox.value.removeEventListener('mousemove', ()=>{})
imgbox.value.removeEventListener('mouseout', ()=>{})
})
</script>
<style scoped>
.mask {
width: 50px;
height: 50px;
background-color: #fff;
opacity: .6;
cursor: crosshair;
position: absolute;
}
.imgBox {
position: relative;
overflow: hidden;
width: 200px;
height: 200px;
}
.zoomBox {
width: 200px;
height: 200px;
position: absolute;
border: 1px solid #eee;
background: #fff;
overflow: hidden;
}
.fade-enter-active, .fade-leave-active {
transition: opacity .5s
}
.fade-enter, .fade-leave-active {
opacity: 0
}
</style>
</script>