use-canvas-drag
v0.6.0
Published
Vue3 画布拖拽组合式函数,支持多种触发方式
Maintainers
Readme
use-canvas-drag
Vue3 画布拖拽组合式函数,轻量、无依赖、TypeScript 支持,开箱即用。
特性
- 🌿 轻量无依赖 - 仅 ~1KB,零外部依赖
- 🔧 多种触发方式 - 支持右键、中键、左键 + 修饰键组合
- ⌨️ 独立方向键模式 - 简单配置
arrowKeys即可启用上下左右微调 - 📦 开箱即用 - 组合式函数设计,天然 Tree-Shakable
- 🔰 TypeScript - 完整类型提示,IDE 友好
- 🎯 零外部依赖 - 不依赖任何 UI 框架
安装
npm install use-canvas-drag
# 或
pnpm add use-canvas-drag
# 或
yarn add use-canvas-drag推荐用法
推荐使用修饰键组合来避免误触发拖拽,这样用户可以正常在画布上进行其他操作(如选中元素),只有在按住修饰键时才触发拖拽:
<template>
<div
id="canvas"
ref="canvasRef"
class="canvas"
@mousedown="handlers.onMouseDown"
@contextmenu="handlers.onContextMenu"
@keydown="handlers.onKeyDown"
>
<!-- 画布内容 -->
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useCanvasDrag } from 'use-canvas-drag'
const canvasRef = ref(null)
const { handlers, isPanning } = useCanvasDrag({
container: () => canvasRef.value,
// 推荐:Shift + 左键 或 Shift + 右键 拖拽
// 光标保持默认,用户可正常操作画布
// 修饰键大小写不敏感:'shift+left' 和 'Shift+Left' 效果相同
mode: ['shift+left', 'shift+right'],
arrowKeys: true,
onDrag: ({ x, y }) => {
console.log('拖拽距离:', x, y)
}
})
</script>
<style scoped>
.canvas {
width: 100%;
height: 500px;
border: 1px solid #ddd;
overflow: auto;
position: relative;
}
/* 无需手动设置 cursor,插件会自动处理 */
</style>优势:
- 🖱️ 按住
Shift+ 鼠标左右键均可拖拽 - 🎯 光标保持默认,不影响画布内的其他交互
- ⌨️ 可配合
arrowKeys实现键盘微调
快速开始
<template>
<div
id="canvas"
ref="canvasRef"
class="canvas"
@mousedown="handlers.onMouseDown"
@contextmenu="handlers.onContextMenu"
@keydown="handlers.onKeyDown"
>
<div class="content">
<div class="item">拖拽滚动画布</div>
<div class="item">拖拽滚动画布</div>
<div class="item">拖拽滚动画布</div>
<div class="item">拖拽滚动画布</div>
<div class="item">拖拽滚动画布</div>
<div class="item">拖拽滚动画布</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useCanvasDrag } from 'use-canvas-drag'
const canvasRef = ref(null)
const { handlers, isPanning } = useCanvasDrag({
container: () => canvasRef.value,
mode: 'left',
onDrag: ({ x, y }) => {
console.log('拖拽距离:', x, y)
}
})
</script>
<style scoped>
.canvas {
width: 100%;
height: 500px;
border: 1px solid #ddd;
overflow: auto;
position: relative;
cursor: grab;
}
.canvas:active {
cursor: grabbing;
}
.content {
width: 1200px;
height: 800px;
display: flex;
flex-wrap: wrap;
gap: 20px;
padding: 20px;
}
.item {
width: 200px;
height: 150px;
background: #4a90e2;
color: white;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
}
</style>鼠标拖拽 + 方向键混合示例
<template>
<div
id="canvas"
ref="canvasRef"
class="canvas"
@mousedown="handlers.onMouseDown"
@contextmenu="handlers.onContextMenu"
@keydown="handlers.onKeyDown"
>
<!-- 画布内容 -->
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useCanvasDrag } from 'use-canvas-drag'
const canvasRef = ref(null)
const { handlers, isPanning } = useCanvasDrag({
container: () => canvasRef.value,
mode: 'left', // 左键拖拽
arrowKeys: true, // 启用方向键微调
onStartDrag: (e) => {
console.log('开始拖拽', e)
},
onDrag: ({ x, y }) => {
console.log('拖拽距离:', x, y)
},
onEndDrag: () => {
console.log('结束拖拽')
}
})
</script>操作方式:
- 🖱️ 左键点击画布并拖拽
- ⌨️ 点击画布后,使用
↑↓←→方向键微调(每次 30px)
自动聚焦机制
插件会在鼠标事件触发时自动设置 tabindex(如不存在),并调用 focus(),确保后续的键盘事件能够正确响应。无需手动在 HTML 中添加 tabindex="0"。
自定义触发规则
import { useCanvasDrag } from 'use-canvas-drag'
import type { DragTrigger, DragButtonConfig } from 'use-canvas-drag'
// 快捷方式
mode: 'right' // 右键拖拽(默认)
mode: 'left' // 左键拖拽
mode: 'middle' // 中键拖拽
// 修饰键组合
mode: 'Shift+left' // Shift + 左键
mode: 'Ctrl+right' // Ctrl + 右键
mode: 'Alt+middle' // Alt + 中键
// 多个触发键
mode: ['left', 'shift+right'] // 左键 或 shift+右键
// 自定义对象
const customMouse: DragButtonConfig = {
button: 0, // 0=左键, 1=中键, 2=右键
modifiers: {
shift: true,
ctrl: true
}
}
const { handlers } = useCanvasDrag({
container: '#canvas',
mode: [customMouse, 'right']
})边界限制
const { handlers } = useCanvasDrag({
container: '#canvas',
mode: 'right',
// 方式1: 自动限制在内容范围内
bounds: true,
// 方式2: 指定精确边界
bounds: {
left: 0,
right: 1000,
top: 0,
bottom: 800
}
})API
useCanvasDrag(options)
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| container | string \| HTMLElement \| () => HTMLElement | ✅ | 画布容器,支持选择器、元素或返回元素的函数 |
| mode | DragTrigger \| DragTrigger[] | ❌ | 鼠标触发方式,默认 'right'。支持 'left' / 'right' / 'middle' / 'Shift+left' 等 |
| arrowKeys | boolean | ❌ | 启用方向键微调(↑↓←→),默认 false |
| bounds | boolean \| 'content' \| { top?: number; right?: number; bottom?: number; left?: number; } | ❌ | 可选边界限制,控制拖拽范围 |
| enabled | boolean \| Ref<boolean> | ❌ | 是否启用,默认 true(支持响应式) |
| onStartDrag | (e: MouseEvent) => void | ❌ | 开始拖拽时触发(仅鼠标模式) |
| onDrag | (info: { x: number; y: number }) => void | ❌ | 拖拽过程中触发(鼠标和方向键模式均触发) |
| onEndDrag | () => void | ❌ | 结束拖拽时触发(仅鼠标模式) |
返回值
| 属性 | 类型 | 说明 |
|------|------|------|
| isPanning | Ref<boolean> | 当前是否正在拖拽 |
| handlers | { onMouseDown, onContextMenu, onKeyDown } | 需要绑定到容器元素 |
| stopPan | () => void | 强制停止拖拽 |
DragTrigger
DragTrigger 支持以下形式:
- 字符串:
'left'、'right'、'middle'、'Shift+left'、'Ctrl+right'等 - 对象:
DragButtonConfig - 数组:组合多个触发规则
// 快捷方式
mode: 'right'
// 修饰键组合
mode: 'Shift+left'
mode: ['Shift+left', 'Ctrl+right']
// 自定义鼠标规则
mode: {
button: 0,
modifiers: { ctrl: true }
}CanvasDragOptions
interface CanvasDragOptions {
container: string | HTMLElement | (() => HTMLElement | null)
mode?: DragTrigger | DragTrigger[]
arrowKeys?: boolean // 启用方向键微调
enabled?: boolean | Ref<boolean>
onStartDrag?: (e: MouseEvent) => void
onDrag?: (detail: { x: number; y: number }) => void
onEndDrag?: () => void
bounds?: boolean | 'content' | {
left?: number
right?: number
top?: number
bottom?: number
}
}DragButtonConfig
interface DragButtonConfig {
button?: number // 0=左键, 1=中键, 2=右键
modifiers?: {
shift?: boolean
ctrl?: boolean
alt?: boolean
meta?: boolean
}
}常见问题
Q: 右键菜单被阻止了吗?
A: 自动处理! 当 mode 配置包含纯右键(不带修饰键)时,插件会自动禁用浏览器右键菜单。若右键带有修饰键(如 shift+right),则不会全局禁用右键菜单。
Q: 光标样式需要手动设置吗?
A: 自动处理! 插件会根据 mode 配置自动切换光标:
- 包含纯左键(不带修饰键)→
grab(默认)/grabbing(拖拽中) - 仅右键、修饰键组合或其他 → 保持默认光标
例如 mode: 'left' 显示 grab,而 mode: 'shift+left' 保持默认光标(需按住 Shift 才触发拖拽)。
Q: 如何使用方向键微调?
A: 设置 arrowKeys: true 即可启用。方向键每次触发移动 30px,无需在 mode 中配置。
useCanvasDrag({
mode: 'left',
arrowKeys: true
})Q: 鼠标模式和方向键模式的区别是什么?
| 特性 | 鼠标模式 | 方向键模式 |
|------|---------|-----------|
| 触发方式 | 按下鼠标按钮 | 按下方向键 |
| 开始/结束回调 | ✅ onStartDrag / onEndDrag | ❌ 无 |
| 拖拽回调 | ✅ onDrag | ✅ onDrag |
| isPanning 状态 | ✅ 支持 | ❌ 不适用 |
Q: 支持多画布吗?
A: 支持,只需为每个画布创建一个 useCanvasDrag 实例即可。
更新日志
v0.5.6 (2026-05-18)
- 🐛 修复修饰键大小写 bug -
parseTrigger中修饰键比较已改用小写,确保'shift+left'、'Shift+Left'、'SHIFT+LEFT'均能正确识别 - ✨ 右键菜单智能禁用 - 只有纯右键(不带修饰键)才自动禁用浏览器右键菜单
- ✨ 光标智能切换 - 只有纯左键(不带修饰键)才自动显示
grab/grabbing光标,修饰键组合保持默认光标
v0.5.1 (2026-05-17)
- 🔧 简化
mode类型 - 移除KeyboardTriggerConfig,鼠标触发器统一使用DragButtonConfig - 🔧 独立方向键模式 - 新增
arrowKeys选项,替代在mode中配置方向键 - 🔧 优化解析逻辑 -
'Alt+left'等组合键正确解析为鼠标触发器
v0.5.0 (2026-05-17)
- ✨ 新增键盘方向键支持 - 支持
ArrowUp、ArrowDown、ArrowLeft、ArrowRight - ✨ 自动聚焦机制 - 鼠标事件触发时自动设置
tabindex并focus() - ✨ 双重触发校验 -
shouldTrigger同时验证修饰键和按键名,防止误触发 - 🔧 优化边界限制 - 新增
bounds: true和bounds: 'content'快捷方式
v0.4.1
- 修复类型导出问题
License
MIT
