HTML5 drag & drop 学习小记

拖拽操作在工作中非常常见,但使用的各种框架、类库都是各位大神的实现,HTML5 专门提供了拖拽与拖放的 API。先后看了 W3school、菜鸟教程以及 MDN 的教程,感觉都不是很理想,前两者教程中各种跳转,看的眼花缭乱的同时大大分散了注意力,而后者则由于自己英文基础差,未翻译的部分始终无法理解其中的含义,无意中看到了张鑫旭大大的文章HTML5 drag & drop 拖拽与拖放简介,顿感豁然开朗。写下心得加深理解,同时备忘(真正理解了是很难忘记的)。

先来一段重点,摘录自「HTML5 drag & drop 拖拽与拖放简介」

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* dataTransfer 对象,拖拽对象用来传递的媒介,使用一般为 event.dataTransfer。
* draggable 属性,需要拖动的元素设置 draggable=true,否则无效。
* ondragstart 事件,当拖拽元素开始被拖拽时触发,此事件作用在被拖拽元素上。如果是这样打字的话,其实还是蛮舒服的。
* ondragenter 事件,当拖拽元素进入目标元素时触发,此事件作用在目标元素上。
* ondragover 事件,当拖拽元素在目标元素上移动时触发,此事件作用在目标元素上。
* ondrop 事件,被拖拽的元素在目标元素上同时鼠标放开触发,此事件作用在目标元素上。
* ondragend 事件,当拖拽完成后触发,此事件作用在被拖拽元素上。
* event.preventDefault() 方法,阻止默认事件。在 ondragover 中一定要执行,否则 ondrop 事件不会被触发。
如果是从其他应用或者文件中拖拽文件,尤其是图片时,默认动作是显示这个图片或是相关信息,并不是真的执行 drop。
此时需要用 document 的 ondragover 事件把它直接干掉。
* event.effectAllowed 属性,就是拖拽效果。
* dataTransfer.setData() 方法,设置被拖拽数据的数据类型和值。
* dataTransfer.getData() 方法,获取被拖拽的数据。该方法将返回在 setData() 方法中设置为相同类型的所有数据。
*/

实例

学习的同时看到文章下面有个小 demo,本着学习理解,将下面的实例进行了实现。

1.html 结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div class="main clearfix">
<div class="dustBox">
<br>
<br>
</div>
<div class="dragBox">
<ul class="dragList">
<li draggable="true">列表1</li>
<li draggable="true">列表2</li>
<li draggable="true">列表3</li>
<li draggable="true">列表4</li>
<li draggable="true">列表5</li>
<li draggable="true">列表6</li>
</ul>
</div>
<div class="dragRemind"></div>
</div>

专业与非专业,从命名就可以看出来,为了彰显自己的“专业”。使用了原文部分 class。

2.css 样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
.clearfix:after {
display: block;
clear: both;
content: "\200B";
height: 0;
}
.clearfix {
*zoom: 1;
}
strong {
color: red;
}
.main {
border: 1px solid #000;
padding: 10px;
width: 460px;
}
.dustBox {
float: left;
width: 100px;
height: 262px;
background-color: #808080;
font-size: 36px;
margin-right: 20px;
display: flex;
-webkit-align-items: center;
align-items: center;
-webkit-justify-content: center;
justify-content: center;
}
.dragBox {
float: right;
}
.dragList {
margin: 0;
padding: 0;
}
.dragList li {
width: 320px;
border: 1px dashed #ccc;
height: 35px;
margin-bottom: 8px;
line-height: 34px;
padding-left: 5px;
list-style: none;
}
.dragRemind {
clear: both;
}

有句话说,很多大厂不敢开源自己的代码,不是因为怕被“copy”,而是怕看完之后发现他们的代码很烂而不想用他们的东西。反正我的代码很烂,那就亮出来吧。

3.js 代码

  1. 获取到所有需要用到的元素,这是毫无疑问的。
1
2
3
4
5
6
let dustBox = document.getElementsByClassName('dustBox')[0],
dragRemind = document.getElementsByClassName('dragRemind')[0],
dragList = document.getElementsByClassName('dragList')[0],
dragItem = dragList.getElementsByTagName('li'),
dragItemLength = dragItem.length,
dustItem = null;
  1. 为每个拖拽项添加拖拽事件。ondragstart 元素开始拖拽时触发,ondragend 拖拽结束后触发。那拖拽中呢?拖拽中的事件由放置目标触发。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
for (let i = 0; i < dragItemLength; i++) {
// ondragstart 元素开始被拖拽
dragItem[i].ondragstart = function () {
return false
}
dragItem[i].ondragstart = function (event) {
/**@effectAllowed 属性
* none: 不能把拖拽元素放在这里,这是除文本框以外所有元素的默认值
* move: 应该把拖拽元素移动到放置目标
* copy: 应该把拖拽元素复制到放置目标
* link: 表示放置目标会打开拖拽元素(拖拽元素必须是一个链接,有 URL)
*/
event.dataTransfer.effectAllowed = 'move';
// 设置拖拽元素的数据类型和值。使用大写的 Text 和 URL 以兼容 Firefox。
event.dataTransfer.setData('Text', event.target.innerText);
// 获取拖拽目标并保存
dustItem = event.target;
return true
}
// ondragend 拖拽完成触发
dragItem[i].ondragend = function (event) {
// 从 dataTransfer 对象中删除指定格式的数据,如果无参数,则删除所有数据。
event.dataTransfer.clearData('Text');
dustItem = null;
return false
}
}
  1. 拖拽目标进入放置目标
1
2
3
4
dustBox.ondragenter = function (event) {
// 做点改变以证明
this.style.color = '#fff';
}
  1. 拖拽目标离开放置文件,准备删除的时候发现拖拽错了,要返回怎么办,当然是把它放回去了。
1
2
3
4
dustBox.ondragleave = function (event) {
// 还原
this.style.color = '#000';
}
  1. 拖拽目标在放置目标上移动
1
2
3
4
dustBox.ondragover = function (event) {
// 默认无法将 数据/元素 放置到其他元素中。如果需要允许放置,必须阻止对元素的默认处理。
event.preventDefault();
}
  1. 拖拽目标在放置目标上且鼠标松开,哦,删除了。
1
2
3
4
5
6
7
8
9
dustBox.ondrop = function (event) {
if (dustItem) {
dragRemind.innerHTML = `<strong>${dustItem.innerText}</strong> 被放进了废纸篓。`
// 从父节点移除要删除的目标
dustItem.parentNode.removeChild(dustItem)
}
this.style.color = '#000';
return false
}

借用星爷的一句话:“打完收工。”

顺带说一下,Markdown 中的代码片段怎么那么丑。
vscode代码片段

0%