拖拽指令
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 | 启用开关。控制是否允许拖拽,动态切换时会自动处理光标样式。 | Boolean | true |
| trigger | 拖拽句柄。CSS 选择器字符串。仅当鼠标在指定子元素上按下时才触发拖拽(例如:只允许按住标题栏拖动)。 | String | el (自身) |
| exclude | 排除区域。CSS 选择器字符串。位于 trigger 内部但不触发拖拽的元素(例如:标题栏上的关闭按钮)。 | String | — |
| containment | 边界限制。是否将元素限制在父容器可视范围内。 | Boolean | true |
| positionType | 定位模式。可选 'transform' 或 'absolute'/'fixed'。'transform': 修改 CSS Translate,性能更好,不破坏文档流。'absolute': 修改 left/top,适用于传统的定位布局。 | String | 'transform' |
| inAdpt | 缩放修正。是否处于 TechUI 的缩放适配容器中。开启后会根据全局 tDom.adpt.info 修正鼠标坐标,防止拖拽漂移。 | Boolean | false |
| resetOnDisable | 禁用重置。当 enabled 变为 false 时,是否清空元素的 style 属性(如重置位置)。 | Boolean | false |
| 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 实现了复杂的坐标计算:
- 初始位置获取 (
getStartPosition):
- Transform 模式: 解析
window.getComputedStyle(el).transform矩阵 (DOMMatrix) 获取当前的 translate X/Y。 - Position 模式: 计算
el.getBoundingClientRect()相对于offsetParent的偏移量。
- 移动增量: 计算
e.clientX - mouseStartX。如果开启了inAdpt,增量会除以全局缩放比例 (scaleX,scaleY),从而保证在缩放页面中鼠标跟手。 - 边界碰撞 (
containCalcTrans/containCalcPos): 预先计算最小和最大允许的 X/Y 值,在mousemove时进行数值钳制 (Clamp)。