VUE3+TS实现图片缩放移动弹窗
完整代码
使用VUE3、TS,实现将图片通过鼠标拖拽缩放以及选择缩放比例。
<template><div><el-dialogv-model="dialogVisible"title="查看图片":close-on-click-modal="false":close-on-press-escape="false"fullscreenstyle="overflow: hidden;"><div style="margin-bottom: 10px;"><el-selectv-model="magnification"placeholder="请选择图片放大尺寸"size="large"style="width: 240px"@change="changePicSize"><el-optionv-for="item in options":key="item.value":label="item.label":value="item.value"/></el-select></div><div class="img_area" ref="container" @wheel.prevent="handleWheel"@mousemove="handleDrag"@mouseup="endDrag"@mouseleave="endDrag"><img :style="imageStyle" class="auto-scale-image" :src="props.imgSrc" ref="image"@mousedown="startDrag"draggable="false"/></div><template #footer></template></el-dialog></div>
</template>
<script lang='ts' setup>// 显隐设置const props = defineProps<{modelValue: boolean,imgSrc:any}>()const emit = defineEmits<{(e: 'update:modelValue', value: boolean): void}>()const dialogVisible = computed({get: () => props.modelValue,set: (value) => emit('update:modelValue', value)})let magnification = $ref(null) as anylet options = [{value: 0.1,label: '0.1',},{value: 1,label: '1',},{value: 2,label: '2',},]const translate = ref({ x: 0, y: 0 });const scale = ref(1);const isDragging = ref(false);const container = ref<HTMLDivElement | null>(null);const step = ref(0.1)const minScale = ref(0.1) const maxScale = ref(3) const imageStyle = computed(() => ({transform: `scale(${scale.value}) translate(${translate.value.x}px, ${translate.value.y}px)`,transformOrigin: 'center center',cursor: isDragging.value ? 'grabbing' : 'grab'}));// 处理鼠标滚轮缩放const handleWheel = (e: WheelEvent) => {if (!container.value) return;const delta = e.deltaY > 0 ? -step.value : step.value;const newScale = Math.max(minScale.value, Math.min(maxScale.value, scale.value + delta));// 计算缩放中心点const rect = container.value.getBoundingClientRect();const mouseX = e.clientX - rect.left;const mouseY = e.clientY - rect.top;// 计算缩放后的偏移量,使鼠标位置保持相对不变const scaleRatio = newScale / scale.value;translate.value = {x: translate.value.x * scaleRatio + (1 - scaleRatio) * (mouseX - rect.width / 2 - translate.value.x),y: translate.value.y * scaleRatio + (1 - scaleRatio) * (mouseY - rect.height / 2 - translate.value.y)};scale.value = newScale;};// 响应式状态const image = ref<HTMLImageElement | null>(null);const startPos = ref({ x: 0, y: 0 });// 开始拖拽const startDrag = (e: MouseEvent) => {if (e.button !== 0) return; // 只响应左键isDragging.value = true;startPos.value = {x: e.clientX - translate.value.x,y: e.clientY - translate.value.y};e.preventDefault();};// 处理拖拽const handleDrag = (e: MouseEvent) => {if (!isDragging.value) return;let newX = e.clientX - startPos.value.x;let newY = e.clientY - startPos.value.y;translate.value = { x: newX, y: newY };};// 结束拖拽const endDrag = () => {isDragging.value = false;};// 通过选择器改变图片大小const changePicSize = () => {scale.value = magnification;centerImage();}// 居中图片const centerImage = () => {if (!container.value) return;const imageContainer = container.value;imageContainer.scrollLeft = (imageContainer.scrollWidth - imageContainer.clientWidth) / 2;imageContainer.scrollTop = (imageContainer.scrollHeight - imageContainer.clientHeight) / 2;};
</script>
<style scope lang="less">.img_area{width: 100%;height: calc(100vh - 130px);text-align: center;.auto-scale-image{max-width: 100%;max-height: 100%;object-fit: contain; /* 保持宽高比 */}}
</style>