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

news2025/5/23 22:19:24

完整代码

使用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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2384182.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PyTorch可视化工具——使用Visdom进行深度学习可视化

文章目录 前置环境Visdom安装并启动VisdomVisdom图形APIVisdom静态更新API详解通用参数说明使用示例Visdom动态更新API详解1. 使用updateappend参数2. ~~使用vis.updateTrace方法~~3. 完整训练监控示例 Visdom可视化操作散点图plot.scatter()散点图案例线性图vis.line()vis.lin…

企业级爬虫进阶开发指南

企业级爬虫进阶开发指南 一、分布式任务调度系统的深度设计 1.1 架构设计原理 图表 1.2 核心代码实现与注释 分布式锁服务 # distributed_lock.py import redis import timeclass DistributedLock:def __init__(self, redis_conn):self.redis = redis_connself.lock_key = …

网络安全-等级保护(等保) 2-7 GB/T 25058—2019 《信息安全技术 网络安全等级保护实施指南》-2019-08-30发布【现行】

################################################################################ GB/T 22239-2019 《信息安全技术 网络安全等级保护基础要求》包含安全物理环境、安全通信网络、安全区域边界、安全计算环境、安全管理中心、安全管理制度、安全管理机构、安全管理人员、安…

数据结构实验10.1:内部排序的基本运算

文章目录 一&#xff0c;实验目的二&#xff0c;实验内容1. 数据生成与初始化2. 排序算法实现&#xff08;1&#xff09;直接插入排序&#xff08;2&#xff09;二分插入排序&#xff08;3&#xff09;希尔排序&#xff08;4&#xff09;冒泡排序&#xff08;5&#xff09;快速…

wps编辑技巧

1、编辑模式 2、图片提取方法&#xff1a;右键保存图片 可以直接右键保存下来看看是否是原始图&#xff0c;如果歪着的图&#xff0c;可能保存下来是正的&#xff0c;直接保存试下 3、加批注

开放世界RPG:无缝地图与动态任务的拓扑学架构

目录 开放世界RPG:无缝地图与动态任务的拓扑学架构引言第一章 地图分块系统1.1 动态加载算法1.2 内存管理模型第二章 任务拓扑网络2.1 任务依赖图2.2 动态可达性分析第三章 NPC行为系统3.1 行为森林架构3.2 日程规划算法第四章 动态事件系统4.1 事件传播模型4.2 玩家影响指标第…

【图像处理入门】1. 数字图像的本质:从像素到色彩模型

作为图像处理的开篇&#xff0c;本文将带你拆解数字图像的底层逻辑&#xff1a;从模拟图像到数字信号的神奇转换&#xff0c;到像素世界的微观构成&#xff0c;再到彩色图像的编码奥秘。通过 Python 代码实战&#xff0c;你将亲手触摸图像的 “基因”—— 像素值&#xff0c;并…

(已解决:基于WSL2技术)Windows11家庭中文版(win11家庭版)如何配置和使用Docker Desktop

目录 问题现象&#xff1a; 问题分析&#xff1a; 拓展&#xff1a; 解决方法&#xff1a; 1、使用WSL2技术&#xff08;亲测有效&#xff09; 注意&#xff1a; 2、开启Hyper-V功能&#xff08;未经亲测&#xff0c;待研究&#xff09; 问题现象&#xff1a; 今天想在本…

Ubuntu20.04部署KVM

文章目录 一. 环境准备关闭防火墙&#xff08;UFW&#xff09;禁用 SELinux更换镜像源检查 CPU 虚拟化支持 二. 安装KVM安装 KVM 及相关组件启动 libvirtd 服务验证安装创建虚拟机 一. 环境准备 4C8G&#xff0c;50G硬盘——VMware Workstation需要给虚拟机开启虚拟化引擎 roo…

OpenCV CUDA 模块图像过滤------创建一个高斯滤波器函数createGaussianFilter()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::cuda::createGaussianFilter 是 OpenCV CUDA 模块中的一个工厂函数&#xff0c;用于创建一个高斯滤波器。这个滤波器可以用来平滑图像&#…

可视化图解算法43:数组中的逆序对

1. 题目 ​牛客网 面试笔试TOP101 描述 在数组中的两个数字&#xff0c;如果前面一个数字大于后面的数字&#xff0c;则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P mod 1000000007 数据范围&…

【Python】使用Python实现调用API获取图片存储到本地

使用Python实现调用API获取图片存储到本地 目录 使用Python实现调用API获取图片存储到本地1、项目概述2、核心功能3、环境准备4、代码实现5、结果查看 1、项目概述 开发一个自动化工具&#xff0c;用于从JSON数据源中提取图像ID&#xff0c;通过调用指定API获取未经压缩的原始…

腾讯2025年校招笔试真题手撕(一)

一、题目 有n 把钥匙&#xff0c;m 个锁&#xff0c;每把锁只能由一把特定的钥匙打开&#xff0c;其他钥匙都无法打开。一把钥匙可能可以打开多把锁&#xff0c;钥匙也可以重复使用。 对于任意一把锁来说&#xff0c;打开它的钥匙是哪一把是等概率的。但你无法事先知道是哪一把…

Vue3 与 Vue2 区别

一、Vue3 与 Vue2 区别 对于生命周期来说&#xff0c;整体上变化不大&#xff0c;只是大部分生命周期钩子名称上 “on”&#xff0c;功能上是类似的。不过有一点需要注意&#xff0c;组合式API的Vue3 中使用生命周期钩子时需要先引入&#xff0c;而 Vue2 在选项API中可以直接…

嵌入式学习笔记 - STM32 U(S)ART 模块HAL 库函数总结

一 串口发送方式&#xff1a; ①轮训方式发送&#xff0c;也就是主动发送&#xff0c;这个容易理解&#xff0c;使用如下函数&#xff1a; HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout); ②中断方式发送&#xff…

【VLNs篇】04:SayNav-为新环境中的动态规划到导航进行大型语言模型的基础构建

栏目内容论文标题SayNav: 为新环境中的动态规划到导航进行大型语言模型的基础构建 (SayNav: Grounding Large Language Models for Dynamic Planning to Navigation in New Environments)研究问题自主代理在未知环境中执行复杂导航任务&#xff08;如MultiON&#xff09;时&…

oracle使用SPM控制执行计划

一 SPM介绍 Oracle在11G中推出了SPM&#xff08;SQL Plan management&#xff09;,SPM是一种主动的稳定执行计划的手段&#xff0c;能够保证只有被验证过的执行计划才会被启用&#xff0c;当由于种种原因&#xff08;比如统计信息的变更&#xff09;而导致目标SQL产生了新的执…

Openwrt下使用ffmpeg配合自建RTSP服务器实现推流

目前在Openwrt下时mjpg_streamer实现UVC摄像头转网络摄像头的方案很多&#xff0c;这种方案视频服在路由模组中&#xff0c;在局域网中使用很方便。但是对于需要远程监控管理的情况&#xff0c;mjpg_streamer不适应&#xff0c;因为不在局域网中的播放器无法访问到路由模组中的…

wifi 如果检查失败,UI 就会出现延迟或缺失打勾的现象。

问题&#xff1a;connectedSsid 的初始化依赖 onCreate 中的状态检查&#xff0c;如果检查失败&#xff0c;UI 就会出现延迟或缺失打勾的现象。 WIFI界面上上的一个标识代表成功连接。重启后出现偶尔不打勾的情况。 原始代码&#xff1a; // if (connectedSsid !…

点云(point cloud):自动驾驶的“三维扫描图“

点云&#xff08;Point Cloud&#xff09;&#xff1a;就是用很多“点”来表示一个物体或场景的三维形状和结构。&#xff08;用点描绘的3D画&#xff0c;好比素描&#xff0c;但不是用线条勾勒&#xff0c;而是“点点点点”拼出物体形状&#xff09; 观察这幅图像&#xff0c;…