不得不知道的JavaScript原生拖放实现

1,532 阅读4分钟

关于拖放最有意思的可能就是可以跨窗格、跨浏览器容器、有时候甚至可以跨应用程序拖动元素 ——红宝书

<body>
  <img src="https://www.baidu.com/img/dong_f17b19f600dbf0bfc9b8bed5836f50be.gif" class="drag-source"/>
  <div class="drop-target"></div>
</body>

以下均基于上述代码

拖动过程

盗来的图😅

拖放事件

触发对象事件名称描述
被拖动元素dragstart开始被拖动时触发
drag拖动过程中持续触发
dragend拖动结束时触发
放置目标元素dragenter开始进入放置目标时触发
dragover进入放置目标中持续触发
dragleave离开放置目标时触发
drop在放置目标释放元素时触发

可拖动能力

HTML5 在所有html元素上规定了一个draggable属性,可通过改变draggable属性值来控制元素是否可被拖动。 默认情况下,图片、链接和文本的draggable值true,其中文本在被选中后才可拖动,而图片链接在任何时候都可拖动。

可放置目标

所有元素都支持放置目标事件,但是这些元素默认不可放置的。可通过在放置目标上,阻止默认行为,将其转换为有效的放置目标。只有有效的可放置目标,才会触发相应的drop事件。

const dropTarget = document.querySelector('.drop-target');
dropTarget.addEventListener('dragenter', function (e) {
  e.preventDefault();
});
dropTarget.addEventListener('dragover', function (e) {
  e.preventDefault();
});

dataTransfer 对象

dataTransfer对象是为解决拖动过程中数据传输需求而生的,该对象是event对象的一个属性,因此在拖放事件外部无法访问dataTransfer对象。其拥有两个主要方法:setData()和getData();

  • setData(dataType, dataValue) dataType 为设置的数据类型,包括任何MIME类型, 例如: text/plain、text/url-list等,IE中的text和URL类型会分别映射为text/plain, text/url-list
  • getData(dataType) 获取dataTransfer对象中相应数据类型的数据值

dataTransfer 对象可以分别保存各种数据类型的一个值,数据之间不会相互覆盖。拖动文本时,浏览器会自动调用setData以text的格式,存储起来。拖动图片、链接时,会自动调用setData以URL的格式存储起来。

作为URL格式存储时,数据会被当作网页中的一个链接🔗,如果将其拖到另一个浏览器窗口的话,会自动导航到该URL

dropEffect和effectAllowed属性

dataTransfer不仅可以进行简单的数据传输,也可以通过其dropEffect和effectAllowed两个属性,确定对被拖动元素和放置目标执行什么操作。

  1. dropEffect 属性告诉浏览器允许哪种放置行为,有且仅有以下4个值。

    • none: 被拖动元素不能放置在这默认
    • move: 被拖动元素应该移动到放置目标
    • copy: 被拖动元素应该复制到放置目标
    • link: 放置目标会导航到被拖动元素(仅在它是URL的情况下) 在把元素拖动到放置目标上时,上述每种值都会导致一种指示光标,但仅仅只是光标会自动变化,如果没有代码的参与,则不会自动移动、复制或链接。
  2. dropEffect 是否生效还需取决于设置的effectAllowed属性的值,effectAllowed 表示被拖动元素允许的行为。包括以下属性值:

    • uninitialized: 没有给被拖动元素设置允许的动作
    • none: 被拖动元素没有被允许的动作
    • copy: 允许copy这种dropEffect
    • move: 允许move这种dropEffect
    • link: 允许link这种dropEffect
    • copyLink: 允许copylink两种dropEffect
    • copyMove: 允许copymove两种dropEffect
    • linkMove: 允许linkmove两种dropEffect
    • all: 允许所有的dropEffect(默认)

dataTransfer对象的其他成员

  • clearData(format) 清除以特定格式存储的数据,如果format未指定,则清除所有格式数据
  • setDragImage(element, x, y) 设置自定义的拖动图像, element 为显示的半透明图片

总结

虽然已经有了许多优秀的库,能够帮助开发者实现复杂的拖放效果,但是了解原生实现也不容忽视。如有错误或不严谨的地方,欢迎批评指正。如果喜欢,欢迎点赞、收藏。

完整代码

codesandbox/drag-and-drop

参考