完整代码
使用VUE3、TS,实现将图片通过鼠标拖拽缩放以及选择缩放比例。
<template>
<div>
<el-dialog
v-model="dialogVisible"
title="查看图片"
:close-on-click-modal="false"
:close-on-press-escape="false"
fullscreen
style="overflow: hidden;"
>
<div style="margin-bottom: 10px;">
<el-select
v-model="magnification"
placeholder="请选择图片放大尺寸"
size="large"
style="width: 240px"
@change="changePicSize"
>
<el-option
v-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 any
let 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>