跳到主要内容位置

Drag&Drop API:实现拖拽操作

Drag&Drop API 是 Web 开发中一个非常有用的功能,它可以让我们实现拖拽操作。本文将介绍如何使用 Drag&Drop API 实现拖拽操作,包括设置元素为可拖拽、定义拖拽事件、设置拖拽效果等。

设置元素为可拖拽

要实现拖拽操作,首先需要将元素设置为可拖拽。我们可以使用 draggable 属性来设置元素是否可拖拽。当 draggable 属性设置为 true 时,元素就可以被拖拽了。例如:

<div draggable="true">可以拖拽的元素</div>

需要注意的是,当元素被设置为可拖拽时,它的默认行为会被禁止,即不再可以选中或复制元素内容。

定义拖拽事件

在设置元素为可拖拽后,我们需要定义拖拽事件来控制拖拽操作。Drag&Drop API 提供了一些事件来处理拖拽操作,包括 dragstartdragenterdragoverdragleavedrop 等事件。

  • dragstart:当拖拽操作开始时触发。在这个事件处理程序中,我们可以设置拖拽效果,例如设置被拖拽元素的样式或元素的数据。
  • dragenter:当拖拽元素进入可拖拽区域时触发。
  • dragover:当拖拽元素在可拖拽区域中移动时不断触发,可以在这个事件处理程序中设置拖拽效果。
  • dragleave:当拖拽元素离开可拖拽区域时触发。
  • drop:当拖拽元素放置在可拖拽区域时触发。在这个事件处理程序中,我们可以处理放置操作,例如将被拖拽元素移动到放置位置。

下面是一个示例,展示如何定义拖拽事件:

const dragElement = document.getElementById('drag');
const dropElement = document.getElementById('drop');

dragElement.addEventListener('dragstart', function(event) {
event.dataTransfer.setData('text/plain', '被拖拽的元素');
event.target.style.opacity = '0.5';
});

dropElement.addEventListener('dragenter', function(event) {
event.preventDefault();
event.target.style.backgroundColor = 'lightgray';
});

dropElement.addEventListener('dragover', function(event) {
event.preventDefault();
});

dropElement.addEventListener('dragleave', function(event) {
event.target.style.backgroundColor = '';
});

dropElement.addEventListener('drop', function(event) {
event.preventDefault();
const data = event.dataTransfer.getData('text/plain');
event.target.innerText = data;
event.target.style.backgroundColor = '';
dragElement.style.opacity= '1';
});

在这个示例中,我们首先获取了一个被拖拽元素和一个可放置元素,并分别为它们注册了相应的拖拽事件。在 dragstart 事件处理程序中,我们使用 event.dataTransfer.setData() 方法设置了被拖拽元素的数据类型和数据,这些数据可以在 drop 事件处理程序中使用。同时,我们也设置了被拖拽元素的透明度为 0.5,以表示它正在被拖拽。

dragenter 事件处理程序中,我们使用 event.preventDefault() 方法阻止了默认行为,并设置了可放置元素的背景色为灰色,表示它可以接受被拖拽元素。

dragover 事件处理程序中,我们同样使用 event.preventDefault() 方法阻止了默认行为,以便在 drop 事件处理程序中能够处理放置操作。

dragleave 事件处理程序中,我们将可放置元素的背景色恢复为默认值,表示它不再可以接受被拖拽元素。

drop事件处理程序中,我们同样使用 event.preventDefault() 方法阻止了默认行为,并使用 event.dataTransfer.getData() 方法获取了被拖拽元素的数据。然后,我们将被拖拽元素的数据放置到可放置元素中,并将可放置元素的背景色恢复为默认值。最后,我们也将被拖拽元素的透明度恢复为 1。

设置拖拽效果

dragstart 事件处理程序中,我们可以设置拖拽效果。Drag&Drop API 提供了一些方法和属性,可以帮助我们设置拖拽效果。

  • event.dataTransfer.effectAllowed:设置被拖拽元素的可允许放置效果。可选值包括 nonecopymovelink。默认值为 move
  • event.dataTransfer.dropEffect:设置拖拽元素的当前放置效果。可选值包括 nonecopymovelink。默认值为 none
  • event.dataTransfer.setDragImage():设置拖拽元素的自定义图片,使其在拖拽过程中显示。这个方法需要传入一个图片元素和一个坐标偏移量作为参数,例如:
const dragElement = document.getElementById('drag');
const dragImage = new Image();
dragImage.src = 'drag-image.png';

dragElement.addEventListener('dragstart', function(event) {
event.dataTransfer.setData('text/plain', '被拖拽的元素');
event.dataTransfer.effectAllowed = 'move';
event.dataTransfer.setDragImage(dragImage, 0, 0);
});

在这个示例中,我们首先创建了一个图片元素,并将其赋值给 dragImage 变量。然后,在 dragstart 事件处理程序中,我们使用 event.dataTransfer.effectAllowed 属性设置了被拖拽元素的可允许放置效果为 move,表示它可以被移动到放置位置。同时,我们也使用 event.dataTransfer.setDragImage() 方法设置了被拖拽元素的自定义图像为 dragImage,这个图像将在拖拽过程中显示,偏移量为 (0, 0)。

拖拽文件

除了可以拖拽元素外,Drag&Drop API 还可以用来拖拽文件。当拖拽文件时,被拖拽元素的数据类型为 Files,可以使用 event.dataTransfer.files 属性来获取拖拽的文件列表。下面是一个示例,展示如何拖拽文件:

<div id="drop-area">拖拽文件到这里</div>
const dropArea = document.getElementById('drop-area');

dropArea.addEventListener('dragover', function(event) {
event.preventDefault();
event.dataTransfer.dropEffect = 'copy';
dropArea.style.backgroundColor = 'lightgray';
});

dropArea.addEventListener('dragleave', function(event) {
dropArea.style.backgroundColor = '';
});

dropArea.addEventListener('drop', function(event) {
event.preventDefault();
const fileList = event.dataTransfer.files;
for (const file of fileList) {
console.log(`拖拽了文件:${file.name}`);
}
dropArea.style.backgroundColor = '';
});

在这个示例中,我们首先获取了一个可放置元素,并为它注册了 dragoverdragleavedrop 事件处理程序。在 dragover 事件处理程序中,我们使用 event.preventDefault() 方法阻止了默认行为,并设置了拖拽元素的放置效果为 copy,表示它可以被复制到放置位置。同时,我们也将可放置元素的背景色设置为灰色,表示它可以接受被拖拽文件。

dragleave 事件处理程序中,我们将可放置元素的背景色恢复为默认值,表示它不再可以接受被拖拽文件。

drop 事件处理程序中,我们同样使用 event.preventDefault() 方法阻止了默认行为,并使用 event.dataTransfer.files 属性获取了拖拽的文件列表。然后,我们可以使用 for-of 循环遍历文件列表,并打印每个文件的名称。最后,我们也将可放置元素的背景色恢复为默认值。

实现拖拽排序

Drag&Drop API 还可以用来实现拖拽排序功能,例如拖拽列表项进行排序。下面是一个示例,展示如何使用 Drag&Drop API 实现拖拽排序:

<ul id="sortable">
<li>列表项1</li>
<li>列表项2</li>
<li>列表项3</li>
<li>列表项4</li>
<li>列表项5</li>
</ul>
const sortableList = document.getElementById('sortable');
let dragItem = null;

sortableList.addEventListener('dragstart', function(event) {
dragItem = event.target;
event.dataTransfer.effectAllowed = 'move';
});

sortableList.addEventListener('dragover', function(event) {
event.preventDefault();
event.dataTransfer.dropEffect = 'move';
const targetItem = event.target;
if (targetItem.tagName === 'LI' && targetItem !== dragItem) {
const rect = targetItem.getBoundingClientRect();
const offset = rect.y + rect.height / 2 > event.clientY ? 'before' : 'after';
if (offset === 'before') {
sortableList.insertBefore(dragItem, targetItem);
} else {
sortableList.insertBefore(dragItem, targetItem.nextSibling);
}
}
});

sortableList.addEventListener('dragend', function(event) {
dragItem = null;
});

在这个示例中,我们首先获取了一个可排序的列表,并为它注册了 dragstartdragoverdragend 事件处理程序。在 dragstart 事件处理程序中,我们将被拖拽的列表项保存到 dragItem 变量中,并设置了它的可允许放置效果为 move,表示它可以被移动到放置位置。

dragover 事件处理程序中,我们使用 event.preventDefault() 方法阻止了默认行为,并设置了拖拽元素的放置效果为 move,表示它可以被移动到放置位置。然后,我们获取了拖拽元素的目标列表项,并判断它是否为列表项,并且不是被拖拽的列表项。如果满足条件,我们使用 getBoundingClientRect() 方法获取了目标列表项的位置信息,并计算出被拖拽列表项应该插入的位置。最后,我们使用 insertBefore() 方法将被拖拽列表项插入到目标列表项的位置。

dragend 事件处理程序中,我们将 dragItem 变量设置为 null,表示拖拽操作结束。

总结

Drag&Drop API 是 Web 开发中非常有用的功能,它可以让我们实现拖拽操作,包括拖拽元素、拖拽文件、拖拽排序等。在使用 Drag&Drop API 实现拖拽操作时,我们需要设置元素为可拖拽,并定义拖拽事件来控制拖拽操作。同时,我们也可以使用 Drag&Drop API 提供的方法和属性来设置拖拽效果,例如设置被拖拽元素的可允许放置效果、设置拖拽元素的当前放置效果等。

提示

一系列的课程让你成为高级前端工程师。课程覆盖工作中所有常用的知识点和背后的使用逻辑,示例全部都为工作项目简化而来,学完即可直接上手开发!

即使你已经是高级前端工程师,在课程里也可能会发现新的知识点和技巧,让你的工作更加轻松!

《React 完全指南》课程,包含 React、React Router 和 Redux 详细介绍,所有示例改编自真实工作代码。点击查看详情。

《Vue 3.x 全家桶完全指南与实战》课程,包括 Vue 3.x、TypeScript、Vue Router 4.x、Vuex 4.x 所有初级到高级的语法特性详解,让你完全胜任 Vue 前端开发的工作。点击查看详情。

《React即时通信UI实战》课程,利用 Storybook、Styled-components、React-Spring 打造属于自己的组件库。

《JavaScript 基础语法详解》本人所著图书,包含 JavaScript 全面的语法知识和新特性, 可在京东、当当、淘宝等各大电商购买