当前位置: 首页 > news >正文

Vue3图片缩放拖拽组件全攻略

Panzoom 图片缩放拖拽组件使用文档

基于Vue 3 + @panzoom/panzoom的图片缩放拖拽组件,支持滚轮缩放和鼠标拖拽,大图自动缩小完整显示,小图 1:1 居中。


目录

  1. 依赖安装
  2. Props 说明
  3. 完整代码
  4. 使用步骤
  5. 功能说明

1. 依赖安装

npminstall@panzoom/panzoom

2. Props 说明

Prop类型必填默认值说明
imageSrcString""图片地址(支持远程 URL 或URL.createObjectURL的 Blob URL)

3. 完整代码

ProcessDialog.vue

<template> <!-- 固定高度容器,作为 panzoom 的视口 --> <div ref="containerRef" class="panzoom-viewport"> <!-- panzoom 控制的目标元素:transform 在这里生效 --> <div ref="panzoomRef" class="panzoom-layer"> <img v-if="imageSrc" :src="imageSrc" alt="图片" class="draggable-image" @load="onImageLoad" /> <el-empty v-else description="暂无图片" /> </div> </div> </template> <script setup> import { ref, watch, nextTick, onBeforeUnmount } from "vue" import Panzoom from "@panzoom/panzoom" /** * Props * - imageSrc: 图片地址(ObjectURL 或远程 URL) */ const props = defineProps({ imageSrc: { type: String, default: "" } }) // ==================== DOM 引用 ==================== const containerRef = ref(null) // 固定高度视口容器 const panzoomRef = ref(null) // panzoom 控制的内容层 let panzoomInstance = null // ==================== Panzoom 实例创建 ==================== /** 创建并配置 panzoom 实例 * @param {HTMLElement} element - 被控制的内容层 DOM * @returns {Panzoom} panzoom 实例 */ function createPanzoom(element) { return Panzoom(element, { maxScale: 5, // 最大放大 5 倍 minScale: 0.05, // 最小缩小到 5% step: 0.15, // 滚轮每格缩放步长 contain: false, // 不限制内容边界,允许自由拖拽 /* 鼠标/触摸事件处理:避免拖拽时误选文本 */ handleStartEvent: (e) => { // 多指触摸 → 允许缩放 if (e.touches && e.touches.length > 1) return true // 非左键 / 非 touch / 非滚轮 → 不拦截 if (e.button !== 0 && e.type !== "touchstart" && e.type !== "wheel") return true e.preventDefault() e.stopPropagation() } }) } // ==================== 自适应缩放 ==================== /** * 内容自适应容器:大图缩小、小图居中,保持完整显示 * 计算公式: * scale = min(容器宽 / 内容宽, 容器高 / 内容高, 1) * panX = (容器宽 - 内容宽 × scale) / 2 * panY = (容器高 - 内容高 × scale) / 2 * * @param {Panzoom} instance - panzoom 实例 * @param {HTMLElement} layerEl - 内容层 DOM */ function autoFit(instance, layerEl) { if (!instance || !layerEl || !containerRef.value) return const pw = containerRef.value.clientWidth const ph = containerRef.value.clientHeight const cw = layerEl.scrollWidth const ch = layerEl.scrollHeight if (cw <= 0 || ch <= 0) return // 刚好完整显示的比例,最大不超过 1(小图不放大) const scale = Math.min(pw / cw, ph / ch, 1) // 先归零 → 设置缩放 → 居中(避免位移累积误差) instance.pan({ x: 0, y: 0 }) instance.setScale(scale) instance.pan({ x: (pw - cw * scale) / 2, y: (ph - ch * scale) / 2 }) } // ==================== 图片加载回调 ==================== /** 图片加载完成后初始化 panzoom + 自适应居中 */ function onImageLoad() { if (!panzoomRef.value || !containerRef.value) return // 销毁旧实例,避免重复创建 if (panzoomInstance) { panzoomInstance.destroy() panzoomInstance = null } panzoomInstance = createPanzoom(panzoomRef.value) // 滚轮事件绑定到外层容器,确保鼠标在容器内任意位置都能缩放 containerRef.value.addEventListener("wheel", panzoomInstance.zoomWithWheel, { passive: false }) // 等浏览器完成布局后自适应 nextTick(() => { requestAnimationFrame(() => autoFit(panzoomInstance, panzoomRef.value)) }) } // ==================== 监听 imageSrc 变化 ==================== watch( () => props.imageSrc, (src) => { if (src) { nextTick(() => { // 如果图片已缓存(loaded),直接初始化 if (panzoomRef.value?.querySelector("img")?.complete) { onImageLoad() } }) } } ) // ==================== 组件销毁时清理 ==================== onBeforeUnmount(() => { if (containerRef.value && panzoomInstance) { containerRef.value.removeEventListener("wheel", panzoomInstance.zoomWithWheel) } if (panzoomInstance) { panzoomInstance.destroy() panzoomInstance = null } }) </script> <style scoped lang="scss"> /* ======== 视口容器:固定高度,裁剪溢出 ======== */ .panzoom-viewport { width: 100%; height: 65vh; overflow: hidden; position: relative; background: #f5f6f8; border: 1px solid #e8eaed; border-radius: 4px; user-select: none; /* 拖拽时不选中文本 */ } /* ======== panzoom 控制的内容层:transform 在这里生效 ======== */ .panzoom-layer { display: inline-block; transform-origin: 0 0; /* 以左上角为缩放原点,配合 autoFit 的 pan 居中 */ } /* ======== 图片样式 ======== */ .draggable-image { display: block; max-width: none; /* 允许图片超出容器,由 panzoom 控制缩放 */ } </style>

4. 使用步骤

第 1 步:安装依赖

npminstall@panzoom/panzoom

第 2 步:在父组件中使用

<template> <div style="padding: 20px;"> <ProcessDialog :image-src="imageUrl" /> </div> </template> <script setup> import { ref } from "vue" import ProcessDialog from "@/views/mytodolist/components/dialogs/ProcessDialog.vue" // 可以是远程 URL const imageUrl = ref("https://example.com/flow-diagram.png") // 或者通过后端 Blob 接口获取 import { diagram } from "@/api/mytodolist/index" async function loadImage(processInstanceId) { const res = await diagram({ processInstanceId }) imageUrl.value = URL.createObjectURL(res) // Blob → ObjectURL } </script>

5. 功能说明

5.1 滚轮缩放

  • 鼠标悬停在图片上,滚动滚轮即可缩放
  • 以鼠标位置为中心点缩放,缩放步长 15%
  • 最大放大 5 倍,最小缩小到 5%

5.2 鼠标拖拽

  • 按住鼠标左键拖动图片
  • 可拖出容器边界(contain: false
  • 支持触摸屏手势拖拽

5.3 自适应显示

图片大小效果
图片 > 容器自动缩小到完整显示,居中
图片 < 容器保持 1:1 原始大小,居中不放大

5.4 生命周期

  • 图片加载完成后自动初始化 panzoom + 自适应居中
  • imageSrc变化时重新初始化
  • 组件销毁时自动清理 panzoom 实例和事件监听

5.5 autoFit 缩放计算公式

scale = min(容器宽 / 图片宽, 容器高 / 图片高, 1) ↑ ↑ 取宽高比中较小的一个 不超过 1(不大) panX = (容器宽 - 图片宽 × scale) / 2 panY = (容器高 - 图片高 × scale) / 2
http://www.jsqmd.com/news/1295571/

相关文章:

  • GNSS定位误差分析:基于Laika的DOP值计算与应用实战
  • 2026年 别墅墙面翻新施工权威推荐:匠心工艺与环保涂装的品质之选 - 优企名品
  • 2026年7月保定铜雕厂家综合实力排行参考 - 起跑123
  • CAVA:终端中的跨平台音频可视化终极指南
  • Xiaomi Miloco终极指南:7个创意场景打造你的AI智能管家
  • 从零搭建AI考研知识体系:用LLM自动构建专业课思维导图+错题归因模型(含可运行Python脚本)
  • C语言中生成随机数的几种方式
  • 终极指南:如何用Qlib Docker快速搭建AI量化投资研究环境
  • 数据库跨地域部署怎么做?全球数据库低延迟方案
  • 3步突破:机器人强化学习从仿真到实物的实战优化路径
  • Kafka-UI技术解析:如何解决Apache Kafka可视化管理难题的完整方案
  • 2026年07月:电力检查井生产厂家综合评估与战略选型参考 - 优企名品
  • 广州荔湾区正规黄金回收,老凤祥足金首饰金条回收,称重透明当场结算 - 逸程奢侈品回收中心
  • 2026年海归求职机构硬实力排行:六家平台多维度观察 - 甄选测评馆
  • 如何彻底告别Windows系统中顽固的Microsoft Edge浏览器?
  • 本科毕业论文开题报告撰写全攻略
  • AI健康咨询结果可信度如何验证?医学信息学博士团队发布首份《多源交叉验证SOP》(含12项黄金校验标准)
  • CosmJS模块化开发:从基础包到自定义Stargate模块全攻略
  • IRust高级功能探索:代码补全、语法高亮与主题定制
  • 拒绝为冗余功能买单!揭秘NGFW“按模块订阅“与“全功能打包“的成本真相
  • 2026年南京双轴撕碎机刀片生产厂家实力解析:聚焦核心工艺与工况匹配能力 - 卓企推荐
  • 北京产业园注册哪家补贴多:【博亚信诚】政策优厚 - 18002239949
  • 数据中心液冷管路选型参考
  • 2026年工业制冷设备源头厂家怎么选,螺杆式制冷压缩机、半封闭制冷压缩机源头厂家靠谱名单参考 - 栗子测评
  • BERT4Rec论文精读:从理论创新到工程实现的桥梁
  • 三方仓储管理系统推荐 多货主计费与大促稳定选型参考
  • Baserow完整指南:如何用开源无代码平台彻底改变你的数据管理方式
  • 阿里云ECS服务器部署网站全流程:从零配置到HTTPS上线
  • 2026年成都别墅改造公司怎么选才靠谱?本地企业有哪些 - 市场沸点
  • dg-ai-notes部署教程:3步搭建你的AI协作学习环境