Skip to content

拖拽指令

v-tui-drag 是 TechUI 的通用拖拽增强指令。它允许开发者通过配置对象,将任意 DOM 元素变为可拖拽状态。该指令不仅支持常规的绝对定位拖拽,还深度优化了 transform 性能模式,并内置了针对大屏缩放场景(Adaptive)的坐标修正逻辑。

核心特性

  • 双模式定位:支持 transform (GPU加速,默认) 和 style.left/top (绝对定位) 两种移动模式。
  • 精细控制:支持指定拖拽句柄 (trigger) 和排除区域 (exclude)。
  • 边界约束:可自动限制元素在父容器范围内移动 (containment)。
  • 缩放适配:内置 inAdpt 参数,解决在大屏 scale 缩放模式下鼠标位移与元素移动不同步的问题。

基础用法

最简单的用法是直接绑定指令,默认开启 containment 且使用 transform 移动。

vue
<template>
  <div class="box" v-tui-drag>
    Drag Me
  </div>
</template>

API 参考

v-tui-drag 接收一个对象作为参数,支持以下配置项:

参数名说明类型默认值
enabled启用开关。控制是否允许拖拽,动态切换时会自动处理光标样式。Booleantrue
trigger拖拽句柄。CSS 选择器字符串。仅当鼠标在指定子元素上按下时才触发拖拽(例如:只允许按住标题栏拖动)。Stringel (自身)
exclude排除区域。CSS 选择器字符串。位于 trigger 内部但不触发拖拽的元素(例如:标题栏上的关闭按钮)。String
containment边界限制。是否将元素限制在父容器可视范围内。Booleantrue
positionType定位模式。可选 'transform''absolute'/'fixed'
'transform': 修改 CSS Translate,性能更好,不破坏文档流。
'absolute': 修改 left/top,适用于传统的定位布局。
String'transform'
inAdpt缩放修正。是否处于 TechUI 的缩放适配容器中。开启后会根据全局 tDom.adpt.info 修正鼠标坐标,防止拖拽漂移。Booleanfalse
resetOnDisable禁用重置。当 enabled 变为 false 时,是否清空元素的 style 属性(如重置位置)。Booleanfalse
uid事件标识。用于区分不同的事件监听器,建议在复杂场景传入唯一 ID。String

典型案例

以下是TechUI组件库中使用v-tui-drag指令的典型案例。

弹窗组件 (Dialog)

这是最经典的使用场景。通常我们希望:

  • 用户只能按住 标题栏 (.dialog-header) 拖动。
  • 点击 关闭按钮 (.dialog-close) 时不会触发拖拽。
  • 全屏模式 (fullscreen) 下禁止拖拽。
  • 限制弹窗不能拖出可视区域。
vue
<template>
  <div 
    class="dialog-inner"
    v-tui-drag="{ 
      enabled: draggable && !fullscreen, // 全屏或配置不可拖拽时禁用
      trigger: '.dialog-header',         // 仅标题栏可拖动
      exclude: '.dialog-close',          // 排除关闭按钮,防止误触
      containment: true,                 // 限制在父容器内
      positionType: 'absolute',          // 使用绝对定位模式 (配合 dialog 的 CSS)
      inAdpt: isInsideAdaptiveBox,       // 如果在缩放容器内,需开启修正
      uid: uniqueId
    }"
  >
    <div class="dialog-header">
      <span>Title</span>
      <button class="dialog-close">X</button>
    </div>
    <div class="dialog-content">...</div>
  </div>
</template>

全局适配容器 (Adaptive Container)

在数据大屏或编辑器场景中,可能需要拖动整个画板。

  • 这里使用 positionType: 'transform' 以获得最佳渲染性能。
  • 开启 resetOnDisable: true,以便在锁定画板时自动复位。
vue
<template>
  <div 
    id="tuiAdptOuter"
    v-tui-drag="{ 
      enabled: state.dragable,       // 由状态控制是否可拖动
      trigger: '#tuiAdpt',           // 整个区域作为句柄
      resetOnDisable: true,          // 禁用时重置 transform 位置
      containment: false,            // 不限制边界,允许拖出视野
      positionType: 'transform',     // 使用 GPU 加速移动
      inAdpt: false,                 // 自身就是适配层,无需再次修正
      uid: 'adpt-drag-001'
    }"
  >
    </div>
</template>

技术细节

坐标计算逻辑

指令内部通过 drag.js 实现了复杂的坐标计算:

  1. 初始位置获取 (getStartPosition):
  • Transform 模式: 解析 window.getComputedStyle(el).transform 矩阵 (DOMMatrix) 获取当前的 translate X/Y。
  • Position 模式: 计算 el.getBoundingClientRect() 相对于 offsetParent 的偏移量。
  1. 移动增量: 计算 e.clientX - mouseStartX。如果开启了 inAdpt,增量会除以全局缩放比例 (scaleX, scaleY),从而保证在缩放页面中鼠标跟手。
  2. 边界碰撞 (containCalcTrans/containCalcPos): 预先计算最小和最大允许的 X/Y 值,在 mousemove 时进行数值钳制 (Clamp)。