VUE3+TS实现图片缩放移动弹窗

完整代码

使用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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值