Skip to content

Commit 8a6698a

Browse files
RSS1102tdesign-bot
andauthored
fix(Tabs): only show draggable state when dragging to draggable item (#5990)
* fix(Tabs): show prohibited state when dragging to non-draggable area chore(useDragSort): optimize code logic chore(Tabs): add a comment to explain the purpose of onDragSort * chore: stash changelog [ci skip] --------- Co-authored-by: tdesign-bot <[email protected]>
1 parent 805eea0 commit 8a6698a

File tree

3 files changed

+51
-15
lines changed

3 files changed

+51
-15
lines changed

packages/components/tabs/tab-nav.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export default defineComponent({
3737
onAdd: tabProps.onAdd,
3838
onRemove: tabProps.onRemove,
3939
dragSort: tabProps.dragSort,
40+
// 在 useDragSort 里会被调用
4041
onDragSort: tabProps.onDragSort,
4142
},
4243
setup(props) {

packages/shared/hooks/useDragSort/index.ts

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
import { onUnmounted } from 'vue';
22

3-
const traversalTabNavs = (tabNavs: HTMLCollection, fn: { (itemNode: any): void; (tabNav: HTMLDivElement): void }) => {
4-
for (const itemNode of tabNavs) {
5-
if (itemNode.getAttribute('draggable')) {
6-
fn(itemNode);
7-
}
8-
}
3+
const traversalTabNavs = (tabNavs: HTMLCollection, fn: (tabNav: HTMLDivElement) => void) => {
4+
Array.from(tabNavs)
5+
.filter((node): node is HTMLDivElement => node instanceof HTMLDivElement && !!node.getAttribute('draggable'))
6+
.forEach(fn);
97
};
108

11-
const handleTarget = (target: EventTarget, tabNavs: HTMLCollection): any => {
12-
let resultTarget;
9+
const handleTarget = (target: EventTarget, tabNavs: HTMLCollection): HTMLDivElement | undefined => {
10+
let resultTarget: HTMLDivElement | undefined;
11+
1312
traversalTabNavs(tabNavs, (itemNode) => {
14-
if (itemNode.contains(target)) {
13+
if (target instanceof Node && itemNode.contains(target)) {
1514
resultTarget = itemNode;
1615
}
1716
});
17+
1818
return resultTarget;
1919
};
2020

2121
export function useDragSort(props: any) {
22-
let navsWrap: HTMLDivElement = null;
22+
let navsWrap: HTMLDivElement | null = null;
2323

2424
// 获取当前正在拖动的tabNav节点
2525
let dragged: HTMLDivElement;
@@ -32,22 +32,47 @@ export function useDragSort(props: any) {
3232
dragged = target;
3333
// 使其半透明
3434
target.style.opacity = '0.5';
35+
36+
// 指定允许的拖拽操作为 move,且兼容 Firefox(需要 setData)
37+
const dt = event.dataTransfer;
38+
if (dt) {
39+
dt.effectAllowed = 'copy';
40+
try {
41+
dt.setData('text/plain', '');
42+
} catch (e) {
43+
// 某些环境下可能抛错,忽略
44+
}
45+
}
3546
};
47+
3648
const dragend = (event: DragEvent) => {
3749
// 重置透明度
3850
(event.target as HTMLDivElement).style.opacity = '';
3951
};
4052
/* 放置目标元素时触发事件 */
4153
const dragover = (event: DragEvent) => {
42-
// 阻止默认动作以启用drop
43-
event.preventDefault();
54+
if (!navsWrap) return;
55+
const target = handleTarget(event.target, navsWrap.children);
56+
const dt = event.dataTransfer;
57+
if (dt) {
58+
// 不可放置目标显示禁止状态
59+
dt.dropEffect = target?.draggable ? 'copy' : 'none';
60+
}
61+
if (target?.draggable) {
62+
// 阻止默认动作以启用drop
63+
event.preventDefault();
64+
}
4465
};
4566
// 当可拖动的元素进入可放置的目标时
4667
const dragenter = (event: DragEvent) => {
4768
// 高亮目标节点
4869
const target = handleTarget(event.target, navsWrap.children);
4970
if (target && target !== dragged && target.draggable) {
50-
target.firstChild.style.outline = '1px dashed #0052d9';
71+
const { firstChild } = target;
72+
if (firstChild instanceof HTMLElement) {
73+
const newStyle = { outline: '1px dashed #0052d9' };
74+
Object.assign(firstChild.style, newStyle);
75+
}
5176
// 进入的节点全部记录下来
5277
if (!enterTargets.includes(target)) {
5378
enterTargets.push(target);
@@ -72,8 +97,12 @@ export function useDragSort(props: any) {
7297
event.preventDefault();
7398

7499
traversalTabNavs(navsWrap.children, (tabNav) => {
75-
tabNav.firstChild.style.outline = 'none';
100+
const firstChild = tabNav.firstChild as HTMLElement;
101+
if (firstChild) {
102+
firstChild.style.outline = 'none';
103+
}
76104
});
105+
77106
// 将拖动的元素到所选择的放置目标节点中
78107
let target = handleTarget(event.target, navsWrap.children);
79108
if (target && target.parentNode !== dragged && target.draggable) {
@@ -82,7 +111,7 @@ export function useDragSort(props: any) {
82111
// 获取放入元素index
83112
const targetIndex = [].indexOf.call(navsWrap.children, target);
84113
if (targetIndex > dragIndex) {
85-
target = navsWrap.children[targetIndex + 1];
114+
target = navsWrap.children[targetIndex + 1] as HTMLDivElement | null;
86115
}
87116

88117
// 当props.theme === "normal" 会多出一个指示条为第一个dom节点,所以需要减1
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
pr_number: 5990
3+
contributor: RSS1102
4+
---
5+
6+
- feat(Tabs): 拖拽至 `draggable =false` 区域时不显示可放置状态? @RSS1102 ([#5990](https://github.com/Tencent/tdesign-vue-next/pull/5990))

0 commit comments

Comments
 (0)