drag 和 drop实现拖拽效果
背景:前几日,有小伙伴问我如何实现物体的拖拽,当时的回答即 onMouseDown、onMouseMove 和 onMouseUp 事件结合起来做。小伙伴当时觉得这么实现非常的麻烦,于是我又提供了另外一种思路,即通过 drag 和 drop 来实现此效果。
drag、drop 是什么
drag
和 drop
是一个 API
,它可以让页面中的绝大部分元素都变得可拖拽,比如,用户可以通过鼠标选择可拖拽元素,将元素拖拽到可放置元素上,并释放鼠标以便放置这些元素。拖拽期间,会有一个拖拽元素的半透明快照跟随鼠标指针。默认情况下,只有图片、链接、选择的文本可以被拖拽。如果想要其他元素可拖拽,则需要在元素上设置 draggable=true
。
<div draggable="true">这是一个可拖拽的元素</div> 复制代码
当拖拽事件发生时,被拖拽的元素会依次触发 onDragStart
、onDrag
和 onDragEnd
,可放置元素会触发 onDragEnter
、onDragOver
和 onDrop
事件,当被拖拽的元素离开可放置元素上方,还会触发 onDragLeave
事件。 如果想把元素放置到可放置元素上,需做如下设置。如果不设置,则可放置元素的 onDrop
事件无法触发。
const onDragEnter = useCallback((e: React.DragEvent) => { e.preventDefault(); }, []); const onDragOver = useCallback((e: React.DragEvent) => { e.preventDefault(); }, []); 复制代码
到此,我们已经可以拖动元素,也可以让元素接收到 onDrop
事件。
传递数据
每一个拖拽事件都有 dataTransfer
对象,可以通过对象上的 setData
方法存储拖拽数据。拖拽数据主要包含两个信息,数据的类型和数据值。一般都会在 onDragStart
事件中存储拖拽数据,在 onDrop
事件中读取数据。使用方法如下:
const onDragStart = useCallback((e: React.DragEvent, item) => { e.dataTransfer.setData('text/plain', '这是一个可拖拽的元素'); }, []); const onDrop = useCallback((e: React.DragEvent, item) => { const data = e.dataTransfer.getData('text/plain'); ... }, []); 复制代码
dataTransfer
对象上 files
属性通常存储从桌面往浏览器中拖拽的文件列表,目前的应用场景大多为拖拽上传。每一个文件上都包含 3 个字段:name
、size
和 type
。 当发生拖动时,浏览器会自动生成一个半透明的图像,并在拖拽过程中跟随鼠标。
DataTransfer 还支持哪些场景
上文所述的大部分拖拽场景都是在同一个浏览器,如果当前需求是把某一个元素从 A 浏览器拖拽到 B 浏览器某一位置,那么我们应该怎么实现呢?乍一看,这样的需求貌似是无法实现的,但是我们使用dataTransfer
就可以做到。如果你想做跨浏览器的拖拽,唯一需要注意的是拖拽数据的类型,现在大部分的应用程序均支持 text/html
、text/plain
和 text/uri-list
。当然,你也可以使用自定义拖拽数据的类型。
text/html
:在contentEditable
的元素中渲染数据。text/plain
:作为代码编辑器的内容、input
元素标签的value
。text/uri-list
:放置在浏览器中,会导航到URL
;如果放置于桌面,则会创建快捷方式。
总结
本文主要讲解 drag
和 drop
的应用,也介绍可以利用这两个 API
可以实现跨浏览器的拖拽。当然,如果你对上述跨端的拖拽场景感兴趣的话,也可以尝试下 Transmat 库,这个库主要简化了在 Web 应用程序中传输和接收数据的过程。
作者:时间小鱼
链接:https://juejin.cn/post/7025873834901241869