vue-drag-resize-rotate
面向 Vue 3 的拖拽 / 缩放 / 旋转组件,适合图片标注、海报编辑、低代码画布、可视化搭建器等需要矩形编辑能力的场景。
功能亮点
- 支持拖拽 / 缩放 / 旋转:支持在画布中自由移动元素、通过 8 个方向触点调整尺寸,并进行 360° 自由旋转。
- 支持锁定宽高比例 / 翻转 / 尺寸与边界限制:支持按固定比例缩放、拖拽触点自由翻转,并限制元素最小 / 最大宽高和画布活动范围。
- 支持嵌套编辑 / 插槽承载:支持父子元素多层嵌套,可通过插槽放入任意内容,也支持通过数据配置渲染节点。
- 支持编辑模式控制:支持切换只读、仅拖拽、仅缩放、禁止旋转、隐藏控件等模式。
- 支持样式定制:支持自定义触点、轮廓、旋转线、尺寸、阴影和 光标图案。
- 支持轻量接入:仅依赖 Vue 3,支持全局插件安装和单组件引入,样式按需手动加载。
适合什么场景
- 图片标注、截图标记、裁剪框调整等轻量编辑工具
- 海报、贴纸、封面图、营销素材等 Web 可视化编辑器
- 低代码搭建器、大屏编辑器、表单设计器中的自由布局节点
- 需要组合元素、嵌套容器、成组编辑的画布类应用
- 需要将编辑结果保存为 JSON Schema 或远端配置的业务系统
安装
pnpm add @liaogn/vue-drag-resize-rotate
# 或
npm install @liaogn/vue-drag-resize-rotate
快速使用
// main.ts
import { createApp } from 'vue'
import VueDragResizeRotate from '@liaogn/vue-drag-resize-rotate'
import '@liaogn/vue-drag-resize-rotate/style.css'
import App from './App.vue'
createApp(App).use(VueDragResizeRotate).mount('#app')
<template>
<vdr :w="200" :h="150" :x="50" :y="50" @dragging="onChange">
<div>drag · resize · rotate</div>
</vdr>
</template>
<script setup lang="ts">
function onChange(pos: { x: number; y: number; w: number; h: number; r: number }) {
console.log(pos)
}
</script>
完整 API 见 Props · Events · Slots · 边界限制。
核心能力
拖拽、缩放、旋转
组件默认展示 8 个缩放触点和 1 个旋转触点:
- 四角触点用于同时改变宽高
- 四边中点触点用于单轴缩放
angle触点用于旋转sticks可传入触点白名单,例如只保留四角缩放,或隐藏旋转控件
交互过程中会触发 dragStart / dragging / dragStop、resizeStart / resizing / resizeStop、rotateStart / rotating / rotateStop 等事件。所有事件回调都会拿到同一份 pos 数据:
interface PosData {
uuid: string | number
x: number
y: number
w: number
h: number
r: number
z: number | string
stick: '' | 'tl' | 'tm' | 'tr' | 'mr' | 'br' | 'bm' | 'bl' | 'ml' | 'angle'
lock: boolean
active: boolean
flipSign: '' | '+' | '-'
}
受控更新
x、y、w、h、r、z 都会响应外部 prop 更新,因此可以把组件作为受控节点使用:
<vdr
:x="rect.x"
:y="rect.y"
:w="rect.w"
:h="rect.h"
:r="rect.r"
@dragging="onUpdate"
@resizing="onUpdate"
@rotating="onUpdate"
/>
这让你可以把用户操作实时写回 Pinia、JSON 配置、后端接口或编辑器历史栈。
交互开关与约束
<vdr
:w="240"
:h="160"
:x="40"
:y="40"
:lock="true"
:min-width="80"
:min-height="60"
:max-width="480"
:max-height="320"
:limit-x="[0, 800]"
:limit-y="[0, 480]"
:sticks="['tl', 'tr', 'br', 'bl', 'angle']"
/>
常用控制项:
| Prop | 作用 |
|---|---|
draggable |
是否允许拖拽整个元素 |
resizeable |
是否允许通过触点缩放 |
rotateable |
是否允许旋转 |
active |
是否显示激活态与控件 |
activeable |
是否允许被激活和操作 |
lock |
是否锁定当前宽高比 |
minWidth / minHeight |
缩放最小尺寸 |
maxWidth / maxHeight |
缩放最大尺寸 |
limitX / limitY |
限制旋转后矩形包围盒在父坐标系内的活动范围 |
sticks |
自定义显示哪些缩放 / 旋转触点 |
边界限制
limit-x / limit-y 可以约束拖拽、缩放和旋转后的矩形范围。边界判断基于旋转后的轴对齐包围盒,适合把节点限制在画布、裁剪区或父级容器内:
<vdr
:w="180"
:h="120"
:x="40"
:y="40"
:r="15"
:limit-x="[20, 620]"
:limit-y="[20, 420]"
/>
两个 prop 可以单独使用;如果旋转后的包围盒仍能放进边界,组件会在需要时微调 x / y 使其回到范围内。详见 边界限制指南。
主题定制
通过覆写 CSS 变量即可换肤,无需 override class:
.my-vdr {
--vdr-stick-color: crimson;
--vdr-stick-border-radius: 2px;
--vdr-stick-size: 20px;
}
完整变量清单见 主题定制。
嵌套示例
<vdr v-bind="root" />
<script setup lang="ts">
const root = {
uuid: 'root',
w: 400, h: 300, x: 40, y: 40,
childrens: [
{ uuid: 'c1', w: 160, h: 100, x: 40, y: 40, r: 15 },
{ uuid: 'c2', w: 100, h: 100, x: 240, y: 140, lock: true },
],
}
</script>
详见 嵌套指南。
插槽与内容承载
默认插槽会跟随组件的尺寸、位置和角度一起变化,可放入图片、文本、业务组件或其他 <vdr>:
<vdr :w="300" :h="200" :x="40" :y="40">
<img src="/cover.jpg" style="width:100%;height:100%;object-fit:cover" />
</vdr>
如果只是设置背景图,也可以直接使用 bg:
<vdr :w="300" :h="200" bg="/cover.jpg" />
版本与兼容
| 版本 | 支持的 Vue | 状态 |
|---|---|---|
^2.x |
Vue 3.3+ | 当前主线 |
^1.x |
Vue 2.6+ | 已停止维护;安装 @liaogn/vue-drag-resize-rotate@^1 |
v1 → v2 迁移指南见 CHANGELOG。
开发
pnpm install
pnpm dev # playground
pnpm docs:dev # 文档站
pnpm type-check
pnpm build # 产出 dist/
参与贡献请见 CONTRIBUTING.md。
License
MIT liaogn