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

完整代码

使用VUE3、TS,实现将图片通过鼠标拖拽缩放以及选择缩放比例。

bash 复制代码
<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>
相关推荐
程序员Sunday15 小时前
JavaScript 事件循环面试题,宏任务与微任务怎么执行|Sunday面试指南
开发语言·javascript·面试·校招·事件循环·程序员sunday
Setsuna_F_Seiei15 小时前
前端转型 Agent 开发 06 之 Agent Memory 记忆系统(让 Agent 更智能,更懂你)
前端·agent·ai编程
志尊宝15 小时前
Vue3 零基础每日笔记(073):keep-alive 页面缓存实战——列表页返回不丢状态
vue.js·笔记·缓存·#vue #前端 #前端开发·#javascript·#vue.js
zhangzeyuaaa16 小时前
Ruby 多线程、GVL(GIL)与 Mutex 完全指南
开发语言·前端·ruby
默_笙16 小时前
🌊 向量库和 ES 都查不出"关系",我只好给奶茶建了一张人脉网
前端·javascript
优选资讯16 小时前
标签打印软件怎么对接 Excel 数据
前端·excel
思无邪6617 小时前
用 AI 做 JS 逆向:从抓包到复现的完整方法论
开发语言·javascript·人工智能
一个风轻云淡17 小时前
GCC 和 GDB命令简单解读
java·linux·前端
u01110267518 小时前
图片处理接口如何统一错误信息 前端提示与后端错误码设计
前端·状态模式
福兮说18 小时前
浏览器里把 iPhone 的 HEIC 转成 JPG:Chrome 解不开、转完大了七成、拍摄时间全丢,六个坑实测
前端·javascript·图像处理·chrome·ios·iphone·heic