20260904232445

This commit is contained in:
oneao committed 2026-09-04 23:24:45 +08:00
1 parent 4e167df0f0
commit 1b01a31252
19 files changed
+1099 -1013

No files matched your search

@@ -168,6 +168,8 @@
margin-right: 4px;
color: #b0b7c3;
cursor: grab;
/* 从手柄按下时不选中行文本(拖拽由 mousedown 启动,不能 preventDefault) */
user-select: none;
}
.tree-node-grip:active {
cursor: grabbing;
@@ -109,13 +109,42 @@ function onContentClick(e) {
function onCheckChange() {
ctx.handleCheck(key.value, props.node)
}
/* ---------- 拖拽:仅最左侧 grip 手柄可发起 ---------- */
// 行默认 draggable=false。整行可拖时,「按下后手抖几像素」就会误起原生拖拽,
// 而松手若没落在合法落点上不会走 drop,行上又没绑 dragend → dragKey 永远清不掉,
// 节点一直挂着 is-dragging(opacity .4),表现就是「点了发灰、移开也灰」。
const gripArmed = ref(false)
const draggableAttr = computed(() =>
ctx.props.draggable && !disabled.value && gripArmed.value ? 'true' : 'false',
)
/** grip 按下:武装本行拖拽(同步写 DOM,dragstart 可能早于 Vue 的 patch) */
function armDrag() {
if (disabled.value || !ctx.props.draggable) return
gripArmed.value = true
rowRef.value?.setAttribute('draggable', 'true')
// 按下但没真拖(不会产生 dragend)时的兜底解除
document.addEventListener('mouseup', disarmDrag, { once: true })
}
function disarmDrag() {
if (!gripArmed.value) return
gripArmed.value = false
rowRef.value?.setAttribute('draggable', 'false')
}
function onDragStart(e) {
if (disabled.value) {
if (disabled.value || !gripArmed.value) {
e.preventDefault()
return
}
ctx.onDragStart(props.node, e)
}
/** 拖拽结束(无论是否落在合法落点):先解除武装,再让容器清理拖拽态 */
function onDragEnd(e) {
disarmDrag()
ctx.onDragEnd(e)
}
onBeforeUnmount(() => document.removeEventListener('mouseup', disarmDrag))
function onDragOver(e) {
ctx.onDragOver(props.node, e)
}
@@ -143,16 +172,23 @@ function onContextMenu(e) {
:aria-expanded="leaf ? undefined : expanded"
:aria-disabled="disabled || undefined"
:tabindex="tabindex"
:draggable="ctx.props.draggable && !disabled ? 'true' : undefined"
:draggable="draggableAttr"
@dragstart="onDragStart"
@dragover="onDragOver"
@dragleave="onDragLeave"
@drop="onDrop"
@dragend="onDragEnd"
@contextmenu.stop="onContextMenu"
>
<span v-if="ctx.props.draggable" class="tree-node-grip" :aria-hidden="true"
><GripVertical
/></span>
<!-- 拖拽手柄:整行唯一可发起拖拽的区域(按下时才把本行置为 draggable) -->
<span
v-if="ctx.props.draggable"
class="tree-node-grip"
title="拖拽调整顺序"
@mousedown="armDrag"
>
<GripVertical :aria-hidden="true" />
</span>
<!-- 展开/收起箭头:叶子占位对齐;懒加载中显示转圈 -->
<span