🚀 仅用 16 行 JavaScript 代码即可实现强大的拖放功能
拖放功能在应用程序中非常实用,它可以简化用户操作流程的很大一部分。然而,我们通常会将这项任务委托给其他库,但这些库可能会使应用程序变得臃肿。其实,如果您只需要一个非常简单的实现,就可以使用拖放 Web API。今天,我将向您展示如何做到这一点!
我们正在制作
这是我们计划构建的基本实现方案:
这段代码只用了 16 行 JavaScript 代码就实现了!
再添加几行代码,我们就能添加更多附加功能!这里有一个包含更多功能的演示!
多试几次,你会发现我们可以
- 仅在特定位置放置元素
- 为我们放入的元素设置样式
- 为拖动元素的原始副本设置样式
- (只需一点小技巧)甚至可以自定义拖动元素的样式!
这一切仅用了30行代码!
它几乎可以在所有桌面浏览器上运行,甚至部分支持 IE 6(!),这应该足以让它正常工作,但它在某些移动浏览器上无法运行。
您可以在这里查看最新的 CanIUse 数据:
使用库来实现这种非常基本的功能对我来说很麻烦,为了避免你们也遇到同样的问题,我想在这里记录一下这个过程!
HTML结构
可以拖进去的地方
你需要一些放置目标才能把东西拖进去,对吧?我们可以使用普通的div元素来添加这些目标:
<div class='drop'></div>
<div class='drop'></div>
<div class='drop'></div>
<div class='drop'></div>
注:在本文中,我将把我们可以空降的地点称为空降目标。
您可以随意添加任意数量的元素,只要元素具有drop我们能够放入其中的类即可。
我们还可以添加一些基本样式,让它们看起来更美观。
* {
box-sizing: border-box;
font-family: sans-serif;
}
.drop {
width: 220px;
height: 45px;
background: #2563EB;
margin-bottom: 10px;
padding: 10px;
border-radius: 3px;
}
要拖动的元素
要让元素可拖动,我们首先需要一个元素!我们可以将元素放置在之前创建的放置目标之一中。它应该看起来像这样。
<div class='drop'>
<div id='drag' draggable='true' ondragstart='event.dataTransfer.setData('text/plain', null)'>
Drag me!
</div>
</div>
<div class='drop'></div>
<div class='drop'></div>
<div class='drop'></div>
注意我们还将该draggable属性设置为 true。每个可拖动元素都需要draggable设置此属性才能实现拖动。
此外,即使draggable设置了属性,也并非所有元素都可以拖动。我们需要通过监听dragstartHTML 中的事件来显式地声明元素是可拖动的。null由于我们没有任何数据要共享,因此我们在这里设置了数据类型text/plain。
我们还可以(再次)添加一些基本样式,让它们看起来更美观。
#drag {
width: 200px;
height: 25px;
border-radius: 3px;
background: black;
color: white;
display: grid;
align-items: center;
justify-content: center;
}
请注意,只要元素draggable设置了属性true并且放置目标具有drop类,以下代码应该就能在所有地方正常工作。
最小实现
为了实现拖放功能,我们只需要 3 个不同的事件监听器。其他的都是锦上添花。
首先,我们需要存储正在拖动的元素。我们可以通过监听dragstart事件来实现这一点。
let dragged;
document.addEventListener('dragstart', event => {
dragged = event.target;
}, false)
每当拖动一个元素时,该元素都会被存储在一个变量中。
接下来,我们可以监听放置事件,以便放置元素。
document.addEventListener('drop', event => {
// Prevent default behaviour (sometimes opening a link)
event.preventDefault();
if (event.target.className === 'drop') {
dragged.parentNode.removeChild(dragged);
event.target.appendChild(dragged);
}
}, false)
无论何时我们放置一个元素,如果该元素是放置目标(具有drop类),我们将把拖动的元素附加到放置目标上。
我们快要完成了,但还需要做一件事才能使之成功。
默认情况下,拖动元素不会执行任何操作,因此为了防止默认行为,我们需要event.preventDefault在每次拖动到放置目标上时调用该函数。
用一行代码就能轻松实现:
document.addEventListener('dragover', event => event.preventDefault(), false);
搞定!只用了16行代码,我们就实现了拖放功能!
以下是它的运行视频:
添加更多功能
即使这种拖放功能有效,也并不好用,感觉不够“自然”。幸运的是,只需几行代码,我们就可以让这种拖放功能变得更好!
对原始拖动元素进行样式设置
当我们拖动一个元素时,该元素的原始副本样式不会改变。如果我们能为这些被拖动的元素添加不同的样式,例如使其透明以显示正在被拖动,效果会更好。
这很容易做到。只需在事件监听器中添加样式即可dragstart。
document.addEventListener('dragstart', event => {
// ...
event.target.style.opacity = 0.5;
// add more styles as you like...
// ...
});
但是,拖拽完成后我们也需要重置样式。我们可以通过监听以下事件来实现dragend:
document.addeventListener('dragend', event => event.target.style.opacity = '', false)
设置落靶样式
我们还可以通过监听dragenter事件来设置目标位置的样式:
document.addEventListener('dragenter', event => {
if (event.target.className === 'drop') event.target.style.background = '#2c41cc';
}, false)
同样,离开元素后我们需要重置样式。我们可以通过监听以下事件来实现dragleave:
document.addEventListener('dragleave', event => {
if (event.target.className === 'drop') event.target.style.background = '';
}, false)
事件停止后,我们还需要重置样式。我们可以通过编辑drop事件来实现这一点。
document.addEventListener('drop', event => {
// ...
if (event.target.className === 'drop') {
event.target.style.background = '';
//...
})
设置拖拽文本的样式
通过一些技巧,我们也可以对拖动的文本进行样式设置!或许我们可以稍微旋转一下元素,让它看起来更自然一些。
我们可以通过设置原始文本的样式,然后在dragstart事件中立即撤销这些样式来实现这一点,这样用户就看不到它了。
listen('dragstart', event => {
// ...
event.target.style.transform = 'rotate(-2deg)';
setTimeout(() => event.target.style.transform = '', 1);
})
现在,拖动复制的图形时,它看起来会旋转!
您现在拥有一个功能齐全的拖放功能!
以下是它的运行视频:
结论
我们把一项通常会委托给库来完成的任务,自己实现了,而且代码量出奇地少。
我希望这能让你意识到,仅仅使用原生 JavaScript 就能完成很多事情。你并非每次都需要库。
你有没有尝试过自己实现拖放功能?欢迎在评论区分享!
文章来源:https://dev.to/siddharthshyniben/a-powerful-drag-and-drop-implementation-in-just-16-lines-of-javascript-d5d


