<template>
<div ref="imgWrapperRef" class="image-viewer__wrapper" v-show="show" @mousewheel.prevent="rollImg($event)">
<div class="image-viewer__mask" @click="show = false"></div>
<span class="image-viewer__btn image-viewer__close" @click="show = false">
<el-icon><Close /></el-icon>
</span>
<div class="image-viewer__canvas">
<img ref="imgRef" :src="url" @mousedown.stop.prevent="moveImg($event)" />
</div>
</div>
</template>
<script setup>
import {ref, defineExpose} from 'vue';
const show = ref(false);
defineProps({
url: {
type: String,
default: ''
},
});
const changeShow = () => {
show.value = !show.value;
}
const imgRef = ref();
let zoomVal = ref(1);
let translateX = ref(0);
let translateY = ref(0);
let preX = ref(0);
let preY = ref(0);
const rollImg = (event) => {
const preZoomVal = zoomVal.value;
zoomVal.value += event.wheelDelta / 1200;
imgRef.value.style.transform = `scale(${zoomVal.value}) rotate(0deg) translate(${translateX.value}px, ${translateY.value}px)`;
preX.value = translateX.value / preZoomVal * zoomVal.value;
preY.value = translateY.value / preZoomVal * zoomVal.value;
}
const imgWrapperRef = ref();
const moveImg = (event) => {
const initX = event.clientX;
const initY = event.clientY;
function move(e) {
translateX.value = (e.clientX - initX + preX.value) / zoomVal.value;
translateY.value = (e.clientY - initY + preY.value) / zoomVal.value;
imgRef.value.style.transform = `scale(${zoomVal.value}) rotate(0deg) translate(${translateX.value}px, ${translateY.value}px)`;
}
imgWrapperRef.value.addEventListener('mousemove', move);
imgRef.value.addEventListener('mouseup', () => {
imgWrapperRef.value.removeEventListener('mousemove', move);
preX.value = translateX.value * zoomVal.value;
preY.value = translateY.value * zoomVal.value;
})
imgWrapperRef.value.addEventListener('mouseout', () => {
imgWrapperRef.value.removeEventListener('mousemove', move);
preX.value = translateX.value * zoomVal.value;
preY.value = translateY.value * zoomVal.value;
})
}
defineExpose({
changeShow,
})
</script>
<style scoped lang="less">
.image-viewer__wrapper {
z-index: 999;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
.image-viewer__mask {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
opacity: .5;
background: #000;
}
.image-viewer__canvas {
position: static;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
user-select: none;
img {
z-index: 1000;
max-width: 100%;
max-height: 100%;
}
}
.image-viewer__btn {
position: absolute;
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
opacity: .8;
cursor: pointer;
box-sizing: border-box;
user-select: none;
}
.image-viewer__close {
width: 44px;
height: 44px;
font-size: 24px;
color: #fff;
background-color: var(--el-text-color-regular);
border-color: #fff;
top: 40px;
right: 40px;
}
}
</style>
vue图片预览
最新推荐文章于 2024-09-13 23:40:08 发布