Skip to content

v-draggable

使元素可在容器或边界内拖拽。

起始版本: 1.2.0

用法

基础用法

vue
<template>
  <div v-draggable class="draggable-box">
    拖拽我
  </div>
</template>

轴向约束

vue
<template>
  <!-- 仅水平 -->
  <div v-draggable="{ axis: 'x' }">仅 X 轴</div>

  <!-- 仅垂直 -->
  <div v-draggable="{ axis: 'y' }">仅 Y 轴</div>
</template>

约束在父容器内

vue
<template>
  <div class="container">
    <div v-draggable="{ constrain: true }" class="box">
      我会保持在容器内
    </div>
  </div>
</template>

带拖拽手柄

vue
<template>
  <div v-draggable="{ handle: '.drag-handle' }" class="panel">
    <div class="drag-handle">⋮⋮ 拖拽这里</div>
    <div class="content">内容区域</div>
  </div>
</template>

API

类型

typescript
type DraggableAxis = 'x' | 'y' | 'both'

interface DraggableOptions {
  /** 拖拽轴向 @default 'both' */
  axis?: DraggableAxis
  /** 约束在父元素内 @default false */
  constrain?: boolean
  /** 边界元素选择器或元素 */
  boundary?: string | HTMLElement | (() => HTMLElement | null)
  /** 拖拽手柄选择器 */
  handle?: string
  /** 是否禁用拖拽 @default false */
  disabled?: boolean
  /** 网格对齐 [x, y] */
  grid?: [number, number]
  /** 开始拖拽回调 */
  onStart?: (position: { x: number, y: number }, event: MouseEvent | TouchEvent) => void
  /** 拖拽回调 */
  onDrag?: (position: { x: number, y: number }, event: MouseEvent | TouchEvent) => void
  /** 结束拖拽回调 */
  onEnd?: (position: { x: number, y: number }, event: MouseEvent | TouchEvent) => void
}

type DraggableBinding = boolean | DraggableOptions

选项

选项类型默认值说明
axis'x' | 'y' | 'both''both'拖拽轴向约束
constrainbooleanfalse约束在父元素内
boundarystring | HTMLElement | Function-自定义边界元素
handlestring-拖拽手柄选择器
disabledbooleanfalse禁用拖拽
grid[number, number]-网格对齐 [x, y]
onStartFunction-开始拖拽回调
onDragFunction-拖拽中回调
onEndFunction-结束拖拽回调

Composable 用法

你也可以使用 useDraggable composable 来实现相同功能:

vue
<script setup>
import { ref, onMounted } from 'vue'
import { useDraggable } from 'directix'

const target = ref(null)
const { position, isDragging, reset, bind } = useDraggable({
  constrain: true,
  onEnd: (pos) => console.log('拖拽结束:', pos)
})

onMounted(() => bind(target.value))
</script>

<template>
  <div ref="target" :class="{ dragging: isDragging }">
    拖拽我!位置: {{ position.x }}, {{ position.y }}
  </div>
</template>

API

typescript
interface UseDraggableOptions {
  /** 拖拽轴向 */
  axis?: DraggableAxis | Ref<DraggableAxis>
  /** 约束在父元素内 */
  constrain?: boolean | Ref<boolean>
  /** 边界元素选择器或元素 */
  boundary?: string | HTMLElement | (() => HTMLElement | null)
  /** 拖拽手柄选择器 */
  handle?: string
  /** 网格对齐 [x, y] */
  grid?: [number, number] | Ref<[number, number]>
  /** 是否禁用拖拽 */
  disabled?: boolean | Ref<boolean>
  /** 开始拖拽回调 */
  onStart?: (position: Position, event: MouseEvent | TouchEvent) => void
  /** 拖拽回调 */
  onDrag?: (position: Position, event: MouseEvent | TouchEvent) => void
  /** 结束拖拽回调 */
  onEnd?: (position: Position, event: MouseEvent | TouchEvent) => void
}

interface UseDraggableReturn {
  /** 当前位置 */
  position: Readonly<Ref<Position>>
  /** 是否正在拖拽 */
  isDragging: Readonly<Ref<boolean>>
  /** 重置位置到原点 */
  reset: () => void
  /** 绑定拖拽行为到元素 */
  bind: (element: HTMLElement) => () => void
}

示例

网格对齐

vue
<template>
  <div v-draggable="{ grid: [40, 40] }" class="grid-item">
    对齐到 40px 网格
  </div>
</template>

可拖拽模态框

vue
<template>
  <div class="modal">
    <div v-draggable="{ handle: '.modal-header' }" class="modal-content">
      <div class="modal-header">
        <h3>可拖拽模态框</h3>
      </div>
      <div class="modal-body">
        内容区域
      </div>
    </div>
  </div>
</template>

基于 MIT 许可发布