Appearance
drag 拖拽指令
为任意元素提供拖拽能力,支持轴向限制、句柄(handle)、容器范围(containment)、位移模式与回调事件。
安装与引入
按需导入(推荐)
ts
import { VDrag } from '@cuixingjian/cui-utils'全局注册
ts
import { createApp } from 'vue'
import { VDrag } from '@cuixingjian/cui-utils'
const app = createApp(App)
app.directive('drag', VDrag)
app.mount('#app')局部注册
vue
<script setup lang="ts">
import { VDrag as vDrag } from '@cuixingjian/cui-utils'
</script>
<template>
<div v-drag>拖拽我</div>
</template>效果演示
交互式演示
通过切换选项体验不同的拖拽配置。
使用代码
基本用法:
vue
<template>
<div v-drag>拖拽我</div>
</template>轴向限制:
vue
<template>
<div v-drag="{ axis: 'x' }">仅 X 轴拖拽</div>
<div v-drag="{ axis: 'y' }">仅 Y 轴拖拽</div>
</template>句柄拖拽:
vue
<template>
<div v-drag="{ handle: '.header' }">
<div class="header">拖拽这里</div>
<div class="body">内容区域</div>
</div>
</template>容器约束:
vue
<template>
<div class="container">
<div v-drag="{ containment: 'parent' }">
仅在父容器内拖拽
</div>
</div>
</template>API 说明
指令值类型
| 类型 | 说明 | 示例 |
|---|---|---|
boolean | 启用/禁用拖拽 | v-drag="true" |
Object | 传入配置对象 | v-drag="{ axis: 'x' }" |
配置选项 (DragOptions)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| disabled | boolean | false | 是否禁用拖拽 |
| axis | 'x' | 'y' | 'both' | 'both' | 拖拽轴向限制 |
| handle | string | HTMLElement | — | 触发拖拽的句柄(选择器或元素) |
| containment | HTMLElement | 'parent' | null | null | 约束拖拽的容器范围 |
| useTransform | boolean | true | 使用 transform 还是 left/top |
| onStart | (e: PointerEvent, state: DragState) => void | — | 拖拽开始回调 |
| onMove | (e: PointerEvent, state: DragState) => void | — | 拖拽中回调 |
| onEnd | (e: PointerEvent, state: DragState) => void | — | 拖拽结束回调 |
回调参数 (DragState)
| 字段 | 类型 | 说明 |
|---|---|---|
| tx | number | 当前位移 X(px) |
| ty | number | 当前位移 Y(px) |
| moving | boolean | 是否处于拖拽中 |
注意事项
位移模式
transform 模式(默认):
- 使用
transform: translate(x, y)更新位置 - 不影响文档流和周围元素布局
- 性能更好,推荐使用
left/top 模式:
- 使用
left和top更新位置 - 需要元素设置
position: absolute或relative - 适合需要精确定位的场景
容器约束
- 容器必须有明确的尺寸
- 元素初始位置应在容器内
- 使用
containment: 'parent'约束在父容器内
句柄拖拽
- 句柄选择器相对当前元素查找
- 确保句柄元素存在且可访问
- 只有拖拽句柄区域才能触发拖拽
移动端支持
- 使用
pointer事件,支持触摸和鼠标 - 自动设置
touch-action: none避免滚动干扰 - 如需允许滚动,在外层容器调整样式
源码展示
展开查看完整源码
ts
import type { Directive } from 'vue'
import { withInstallDirective } from '../install'
export interface DragOptions {
disabled?: boolean
axis?: 'x' | 'y' | 'both'
handle?: string | HTMLElement
containment?: HTMLElement | 'parent' | null
useTransform?: boolean
onStart?: (e: PointerEvent, state: DragState) => void
onMove?: (e: PointerEvent, state: DragState) => void
onEnd?: (e: PointerEvent, state: DragState) => void
}
export interface DragState {
tx: number
ty: number
moving: boolean
}
// 详见 packages/utils/directives/drag.ts
export const VDrag = withInstallDirective(drag, 'drag')