Skip to content

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)

参数类型默认值说明
disabledbooleanfalse是否禁用拖拽
axis'x' | 'y' | 'both''both'拖拽轴向限制
handlestring | HTMLElement触发拖拽的句柄(选择器或元素)
containmentHTMLElement | 'parent' | nullnull约束拖拽的容器范围
useTransformbooleantrue使用 transform 还是 left/top
onStart(e: PointerEvent, state: DragState) => void拖拽开始回调
onMove(e: PointerEvent, state: DragState) => void拖拽中回调
onEnd(e: PointerEvent, state: DragState) => void拖拽结束回调

回调参数 (DragState)

字段类型说明
txnumber当前位移 X(px)
tynumber当前位移 Y(px)
movingboolean是否处于拖拽中

注意事项

位移模式

transform 模式(默认):

  • 使用 transform: translate(x, y) 更新位置
  • 不影响文档流和周围元素布局
  • 性能更好,推荐使用

left/top 模式:

  • 使用 lefttop 更新位置
  • 需要元素设置 position: absoluterelative
  • 适合需要精确定位的场景

容器约束

  • 容器必须有明确的尺寸
  • 元素初始位置应在容器内
  • 使用 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')