v3-drag-zoom

一个轻量、高效的缩放拖拽逐渐,帮助开发人员快速实现类似地图缩放拖拽等功能
4,424
Install
npm install v3-drag-zoom
Latest Version:1.3.1
Vue:3
License:MIT
Last Updated:May 20, 2026
Links: Gitee  ·  npm
Maintainer: fangjc1986

V3DragZoom

一个基于 vue3 开发的轻量、高效缩放拖拽组件,方便开发者快速实现缩放拖拽功能。

📖 中文文档 | 📖 English Documentation

需要 Vue 2 版本?查看 v2-drag-zoom

在线演示和使用手册(DEMO)

GIT地址

https://gitee.com/ericfang/v3-drag-zoom

🚀 特性

  • ✅ 支持拖拽和缩放功能
  • ✅ 支持多种对齐模式(cover、contain、auto)
  • ✅ 支持跟随鼠标缩放
  • ✅ 支持固定大小的子元素
  • ✅ 支持自定义标记点
  • ✅ TypeScript 原生支持
  • ✅ 响应式设计,自动适应容器大小变化
  • ✅ 平滑动画过渡效果
  • ✅ 支持加载状态显示
  • ✅ Composition API 设计

📦 安装

使用以下命令安装 v3-drag-zoom:

npm install v3-drag-zoom
# 或
yarn add v3-drag-zoom

🎯 用途介绍

V3 Drag Zoom 是一个专为 Vue 3 设计的交互式缩放拖拽组件,适用于需要实现以下功能的场景:

  • 地图应用:实现地图的缩放和平移功能
  • 图片查看器:支持图片的放大缩小和拖拽浏览
  • 图表交互:允许用户缩放和移动复杂的数据可视化图表
  • 设计工具:提供画布的缩放和拖拽能力
  • 文档预览:支持大型文档或图纸的局部查看
  • 虚拟现实界面:创建可交互的 3D 或 2.5D 界面元素

🏗️ 架构介绍

该组件采用模块化设计,主要包含两个核心组件:

V3DragZoomContainer

主容器组件,负责管理整体的缩放和拖拽逻辑,包括:

  • 容器尺寸检测和自适应
  • 缩放计算和动画控制
  • 鼠标事件处理
  • 子组件协调
  • 使用 Composition API 实现

V3DragZoomItem

子项组件,用于在可缩放容器内放置可交互的元素,如:

  • 标记点
  • 注释
  • 图标
  • 其他自定义内容

组件间通过 Vue 的 provide/inject 机制进行通信,确保良好的解耦和可扩展性。

💻 导入组件

全局导入

在 main.js 中全局引入 v3-drag-zoom:

import {createApp} from "vue";
import App from "./App.vue";
// v3-drag-zoom 组件
import V3DragZoom from "v3-drag-zoom";
// v3-drag-zoom 全局样式(必须导入,否则无法正常使用)
import "v3-drag-zoom/dist/style.css";

createApp(App).use(V3DragZoom).mount("#app");

按需导入

在需要的组件中导入 v3-drag-zoom:

<script setup lang="ts">
  import {V3DragZoomContainer, V3DragZoomItem} from "v3-drag-zoom";
</script>

<template>
  <v3-drag-zoom-container>
    <div>需要缩放与拖拽的元素</div>
    <v3-drag-zoom-item :position="{ x: 50, y: 50 }" :draggable="true">
      <span>标记点</span>
    </v3-drag-zoom-item>
  </v3-drag-zoom-container>
</template>

📖 使用示例

基础用法

<template>
  <div style="width: 800px; height: 600px;">
    <v3-drag-zoom-container
      ref="containerRef"
      align="contain"
      :follow-pointer="true"
      @onMove="handleMove"
      @onZoom="handleZoom"
    >
      <!-- 主要内容 -->
      
      
      <!-- 标记点 -->
      <v3-drag-zoom-item
        :position="{ x: 50, y: 50 }"
        :draggable="true"
        :fixed-size="false"
        @onMove="handleItemMove"
      >
        <span>标记点</span>
      </v3-drag-zoom-item>
    </v3-drag-zoom-container>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { V3DragZoomContainer, V3DragZoomItem } from 'v3-drag-zoom';

const containerRef = ref();

const handleMove = (event) => {
  console.log('容器移动:', event);
};

const handleZoom = (event) => {
  console.log('容器缩放:', event);
};

const handleItemMove = (position) => {
  console.log('项目移动:', position);
};
</script>

完整示例

<template>
  <div class="app">
    <h1>V3 Drag Zoom 演示</h1>
    
    <div class="controls">
      <button @click="resetView">重置视图</button>
      <button @click="zoomIn">放大</button>
      <button @click="zoomOut">缩小</button>
    </div>
    
    <v3-drag-zoom-container
      ref="container"
      align="contain"
      :max-zoom="5"
      :min-zoom="0.1"
      :follow-pointer="true"
      :animate-duration="300"
      style="width: 100%; height: 600px; border: 1px solid #ccc;"
    >
      
      
      <!-- 多个标记点 -->
      <v3-drag-zoom-item
        v-for="(marker, index) in markers"
        :key="index"
        :position="marker.position"
        :draggable="true"
        :fixed-size="false"
        @onMove="updateMarkerPosition(index, $event)"
      >
        <div class="marker">
          {{ marker.label }}
        </div>
      </v3-drag-zoom-item>
    </v3-drag-zoom-container>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { V3DragZoomContainer, V3DragZoomItem } from 'v3-drag-zoom';

interface Marker {
  position: { x: number; y: number };
  label: string;
}

const container = ref();
const markers = ref<Marker[]>([
  { position: { x: 20, y: 30 }, label: '地点A' },
  { position: { x: 60, y: 40 }, label: '地点B' },
  { position: { x: 40, y: 70 }, label: '地点C' }
]);

const resetView = () => {
  container.value?.reset();
};

const zoomIn = () => {
  container.value?.zoom(0.2); // 放大20%
};

const zoomOut = () => {
  container.value?.zoom(-0.2); // 缩小20%
};

const updateMarkerPosition = (index: number, newPosition: any) => {
  markers.value[index].position = newPosition;
};
</script>

<style scoped>
.marker {
  background: red;
  color: white;
  padding: 5px 10px;
  border-radius: 15px;
  font-size: 12px;
  cursor: pointer;
}

.controls {
  margin-bottom: 10px;
}

.controls button {
  margin-right: 10px;
  padding: 5px 15px;
}
</style>

📚 API参数

v3-drag-zoom-container

Props
参数名 类型 默认值 说明
align String contain 内容对齐方式,可选值有 auto、 contain、cover
autoResize Boolean true 是否自动重置尺寸,当容器尺寸为百分比的时候,会根据父容器变化而自动变化
followPointer Boolean true 缩放时是否跟随鼠标
maxZoom Float 100 最大缩放倍数
minZoom Float 0.01 最小缩放倍数
zoomFactor Float 0.1 鼠标滚轮一次的缩放比例
loading Boolean false 是否加载中
animateDuration Number 200 缩放时候的过度动画时长,单位 ms
draggable Boolean true 是否可拖拽
zoomable Boolean true 是否可缩放
Events
事件名 参数 说明
onMove ( event :ContainerEvent)=> void 每移动一点距离触发,返回当前位置
onMoveFinished ( event :ContainerEvent)=> void 移动结束(鼠标抬起或超出范围)触发, 返回当前位置
onZoom ( event :ContainerEvent)=> void 缩放触发,返回当前缩放倍数
Slots
Slot 说明
default 直接填写需要放置的内容
loading 自定义加载状态显示内容
Exposed
参数名 类型 说明
zoom (zoom:Float) => void 手动缩放 zoom: 为缩放因子
reset () => void 重置缩放

v3-drag-zoom-item

Props
参数名 类型 默认值 是否必须 说明
offset Array<Integer> [-50,-50] 否 偏移量,默认值代表横向和纵向均偏移 -50%,也就是对齐中心点位置,偏移量单位为 %, 不支持 px
fixedSize Boolean false 否 是否固定大小, true代表在缩放过程中该item内容尺寸不变
rotate Float 0 否 旋转角度单位 deg (360度)
draggable Boolean false 否 是否可以拖拽移动
position(v-model) CurPosition 无 是 该 item 在内容中的位置(百分比位置)
Slots
Slot 说明
default 直接填写需要放置的内容
Events
事件名 参数 说明
onMove ( pos :Position)=> void 每移动一点距离触发,返回当前位置
onMoveFinished ( pos :Position)=> void 移动结束(鼠标抬起或超出范围)触发, 返回当前位置
update:position ( pos :Position)=> void 位置更新时触发(支持 v-model)

类型定义

CurPosition

参数名 类型 默认值 是否必须 说明
x Float 无 是 横向位置 %
y Float 无 是 纵向位置 %

Position extend CurPosition

参数名 类型 默认值 是否必须 说明
x Float 无 是 横向位置 %
y Float 无 是 纵向位置 %
sub (pos:Position)=>Position 无 否 计算当前 Position 与 pos 之间的差值 new Position(this.x - pos.x, this.y - pos.y);
add (pos:Position)=>Position 无 否 计算当前 Position 与 pos 之间的和值 new Position(this.x + pos.x, this.y + pos.y);

Size

参数名 类型 默认值 是否必须 说明
width Integer 无 是 宽度 像素
height Integer 无 是 高度 像素

ContainerEvent

参数名 类型 默认值 是否必须 说明
center CurPosition 无 是 容器中心位置(相对于容器左上角的绝对像素坐标)
containerSize Size 无 是 容器大小(像素)
contentSize Size 无 是 内容大小(像素)
zoom Float 无 是 缩放倍数

🔧 开发

# 安装依赖
npm install

# 启动开发服务器
npm run dev

# 构建
npm run build

🤝 贡献指南

欢迎提交 Issue 和 Pull Request 来改进这个项目。

📄 License

MIT

Related Packages

@minogin/vue-drag-resize-rotate

Vue component which acts as a draggable, resizable and rotateable container for...

7,341 78
vue-grid-layout

A draggable and resizable grid layout, as a Vue component.

2,102,559 7,398
vue3-grid-layout-next

A draggable and resizable grid layout, as a Vue component.

773,720 129
vue-grid-layout-v3

A draggable and resizable grid layout, as a Vue component.

429,159 113
@corvina/vue-grid-layout

A draggable and resizable grid layout, as a Vue component.

4,536 0

Version History

Version Released Vue License
1.3.1 ^3.3.4 MIT
1.3.0 ^3.3.4 MIT
1.2.1 ^3.3.4 MIT
1.2.0 ^3.3.4 MIT
1.1.20 ^3.3.4 MIT