Skip to content

Commit 95b3cc6

Browse files
authored
修改可排序拖拽的bug (DevCloudFE#1144)
1 parent 52a93a6 commit 95b3cc6

File tree

3 files changed

+131
-32
lines changed

3 files changed

+131
-32
lines changed

packages/devui-vue/devui/dragdrop/src/droppable-directive.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export default {
2525
el.addEventListener('drop', (event: DragEvent) => {
2626
event.preventDefault();
2727
const dragId = binding.instance.$root.identity;
28+
document.getElementById(dragId).dataset.parent = 'without-drop';
2829
if (document.getElementById(dragId).dataset.dropArea == document.getElementById(dragId).dataset.dragArea){
2930
return;
3031
}
Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { shadowId } from './constant';
2-
import { changeDragState, createInsertSortableShadow, insertDragElement } from './utils';
2+
import { changeDragState, createInsertSortableShadow, insertDragElement, judgeMouseIsInSortableArea,
3+
exchangeShadowPosition, sameOriginExchangeElementPosition } from './utils';
34

45

56
export default {
@@ -8,41 +9,58 @@ export default {
89
* @param el
910
* @description
1011
* 此命令用于将元素变为可放置的元素并且支持排序
11-
* dragover:
12-
* 1、说明此时进入可排序放置的区域
13-
* 2、此时应该生成相应的可排序的shadow
14-
* drop:
15-
* 1、可放置区域里如果没有拖拽元素,直接放置
16-
* 2、可放置区域里如果有其他的可拖拽元素,需要对比放置到正确的位置上
12+
* 功能分析
13+
* 1、非自身区域内拖动,生成shadow
14+
* 2、自身区域内拖动,不生成shadow
15+
* 实现分析(根据ng-devui)
16+
* shadow的生成规则
17+
* shadow的生成位置
18+
* 待思考问题
19+
* 1、整个拖拽过程中,是否有必要添加节流防抖?
1720
*/
1821
mounted(el: HTMLElement, binding: unknown): void {
22+
const self = el;
1923
el.addEventListener('dragover', function (event: DragEvent){
2024
event.preventDefault();
21-
const targetNode: any = event.target;
25+
const dropArea = [...el.childNodes][1];
2226
const dragId = binding.instance.$root.identity;
23-
if (!binding.instance.$root.dropElement){
24-
binding.instance.$root.dropElement = [...el.childNodes][1];
27+
if (document.getElementById(dragId)?.dataset.parent === 'sort-drop'){
28+
// 说明此时是同源操作(不需要生成shadow)
29+
// sameOriginExchangeElementPosition(event, [...dropArea.children], dragId, dropArea);
30+
return;
2531
}
26-
changeDragState(document.getElementById(binding.instance.$root.identity), binding.instance.$root.identity, 'true', 'false', 'true', 'false', 'true', 'false');
27-
const { dragover, shouldCreateShadow } = document.getElementById(dragId).dataset;
28-
if (dragover == 'true'){
29-
if (shouldCreateShadow == 'true'){
30-
createInsertSortableShadow([...targetNode.children][1], event, dragId);
31-
}
32+
// 需要判定是否存在阴影,否则会出现严重的抖动情况
33+
if (!document.getElementById('shadow0611') && [...self.childNodes[1].children].length === 0){
34+
createInsertSortableShadow([...self.childNodes][1], event, dragId);
35+
} else if ([...self.childNodes[1].children].length >= 1){
36+
// 说明此时想要进行换位操作
37+
// 需要得到此时shadow的位置,遇到shadow则跳过,否则当鼠标出现在shadow上时,会出现严重的抖动操作
38+
exchangeShadowPosition(event, [...self.childNodes[1].children], dragId, self.childNodes[1]);
3239
}
33-
3440
});
3541
el.addEventListener('drop', function (event: DragEvent){
3642
// 获取可放置区域
3743
const dropArea = [...el.childNodes][1];
3844
const dragId = binding.instance.$root.identity;
39-
dropArea.removeChild(document.getElementById(shadowId));
40-
if ([...dropArea.childNodes].length == 0){
41-
dropArea.appendChild(document.getElementById(dragId));
42-
}else {
43-
insertDragElement(dropArea, dragId, event);
45+
if (document.getElementById(dragId)?.dataset.parent === 'sort-drop'){
46+
// 说明是同源(不产生shadow,直接替换)
47+
sameOriginExchangeElementPosition(event, [...dropArea.children], dragId, dropArea);
48+
return;
49+
}
50+
// 判断鼠标是否处于drop区域
51+
if (document.getElementById(shadowId)){
52+
dropArea.replaceChild(document.getElementById(dragId), document.getElementById(shadowId));
53+
if (document.getElementById(dragId)){
54+
document.getElementById(dragId).dataset.parent = 'sort-drop';
55+
}
56+
}
57+
});
58+
// 主要用来移除shadow
59+
el.addEventListener('dragleave', function (event: Event){
60+
const dropArea = [...el.childNodes][1];
61+
if (document.getElementById(shadowId) && !judgeMouseIsInSortableArea(event, el)){
62+
dropArea.removeChild(document.getElementById(shadowId));
4463
}
45-
changeDragState(document.getElementById(dragId), dragId, 'false', 'false', 'false', 'true', 'false', 'false');
4664
});
4765
}
48-
};
66+
};

packages/devui-vue/devui/dragdrop/src/utils.ts

Lines changed: 88 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ function computeCompareElementHeight (compareElement: HTMLCollection): unknown{
7474
*/
7575
function createInsertSortableShadow (sortDropArea: unknown, mouseObject: unknown, originId: string): void {
7676
const sortDropAreaArr: Array = [...sortDropArea.children];
77-
if (sortDropAreaArr.length == 0){
77+
if (sortDropAreaArr.length === 0){
7878
if (!document.getElementById(shadowId)){
7979
const shadowElement = createShadow(originId);
8080
sortDropArea.appendChild(shadowElement);
@@ -83,13 +83,11 @@ function createInsertSortableShadow (sortDropArea: unknown, mouseObject: unknown
8383
for (let index = 0; index < sortDropAreaArr.length; index++){
8484
const compareHeight = computeCompareElementHeight(sortDropAreaArr[index]);
8585
document.getElementById(shadowId) ? sortDropArea.removeChild(document.getElementById(shadowId)) : null;
86-
if (index == sortDropAreaArr.length-1){
87-
sortDropArea.appendChild(createShadow(originId));
88-
break;
89-
}
90-
if (Math.floor(mouseObject.clientY)<= compareHeight){
86+
if (Math.floor(mouseObject.clientY) <= (Math.floor(compareHeight / 2) + sortDropAreaArr[index].getBoundingClientRect().top)){
9187
sortDropArea.insertBefore(createShadow(originId), sortDropAreaArr[index]);
9288
break;
89+
} else {
90+
index === sortDropAreaArr.length - 1 && sortDropArea.appendChild(createShadow(originId));
9391
}
9492
}
9593
}
@@ -132,12 +130,94 @@ function deleteInsertedSortableShadow (dropSortArea: unknown): void{
132130
}
133131
}
134132

133+
/**
134+
*
135+
* @param mouse
136+
* @param sortableArea
137+
* @returns
138+
* @description 判断鼠标是否处于目标元素中
139+
*/
140+
function judgeMouseIsInSortableArea (mouse: MouseEvent, sortableArea: Element): boolean{
141+
const { clientX, clientY } = mouse;
142+
// 获取元素的位置
143+
const eleLeft1 = sortableArea.getBoundingClientRect().left;
144+
const eleLeft2 = sortableArea.getBoundingClientRect().right;
145+
const eletop1 = sortableArea.getBoundingClientRect().top;
146+
const eletop2 = sortableArea.getBoundingClientRect().bottom;
147+
148+
if ((clientX > eleLeft1) && (clientX < eleLeft2) && (clientY > eletop1) && (clientY < eletop2)){
149+
return true;
150+
} else {
151+
return false;
152+
}
153+
154+
}
155+
156+
/**
157+
*
158+
* @param mouse
159+
* @param comparedArr
160+
* @description 同源交换位置
161+
*/
162+
function sameOriginExchangeElementPosition (mouse: Event, comparedArr: Array, dragId: string, dropArea: Element): void{
163+
if (comparedArr.length <= 1){
164+
return;
165+
}
166+
for (let index = 0; index < comparedArr.length; index++){
167+
if (mouse.clientY < comparedArr[index].getBoundingClientRect().top){
168+
dropArea.insertBefore(document.getElementById(dragId), comparedArr[index]);
169+
break;
170+
}
171+
if (index === comparedArr.length - 1 && (mouse.clientY > comparedArr[index].getBoundingClientRect().bottom)){
172+
dropArea.appendChild(document.getElementById(dragId));
173+
break;
174+
}
175+
}
176+
}
177+
178+
/**
179+
*
180+
* @param mouse 当前鼠标对象
181+
* @param comparedArr 待比较的数组
182+
* @description
183+
*/
184+
function exchangeShadowPosition (mouse: Event, comparedArr: Array, dragId: string, dropArea: Element): void{
185+
for (let index = 0; index < comparedArr.length; index++){
186+
// 遇到shadow,直接跳过
187+
if (comparedArr[index]?.id !== 'shadow0611'){
188+
if (Math.floor(mouse.clientY) <= (comparedArr[index].getBoundingClientRect().top)){
189+
console.log('------');
190+
if (comparedArr[index-1]?.id !== 'shadow0611'){
191+
if (document.getElementById('shadow0611')){
192+
dropArea.removeChild(document.getElementById('shadow0611'));
193+
}
194+
dropArea.insertBefore(createShadow(dragId), comparedArr[index]);
195+
break;
196+
}
197+
}
198+
if (Math.floor(mouse.clientY) > (
199+
comparedArr[comparedArr.length - 1].getBoundingClientRect().top)){
200+
if (index === comparedArr.length - 1 && comparedArr[index]?.id !== 'shadow0611'){
201+
// 如果存在shadow,则清除
202+
if (document.getElementById('shadow0611')){
203+
dropArea.removeChild(document.getElementById('shadow0611'));
204+
}
205+
dropArea.appendChild(createShadow(dragId));
206+
}
207+
break;
208+
}
209+
}
210+
}
211+
}
135212

136213
export {
137214
createShadow,
138215
changeDragState,
139216
createInsertSortableShadow,
140217
deleteInsertedSortableShadow,
141218
computeCompareElementHeight,
142-
insertDragElement
143-
};
219+
insertDragElement,
220+
judgeMouseIsInSortableArea,
221+
exchangeShadowPosition,
222+
sameOriginExchangeElementPosition
223+
};

0 commit comments

Comments
 (0)