如何使用 Vanilla JavaScript 和 HTML 创建拖放元素

介绍

拖放是常见的用户交互,您可以在许多图形用户界面中找到。

但是,有些情况下,库可能无法使用,或者引入了项目不需要的过剩或依赖性,在这些情况下,对现代Web浏览器中可用的API的知识可以提供替代解决方案。

HTML Drag and Drop API依靠DOM的事件模型来获取被拖拉或放下的东西的信息,并在拖拉或放下时更新该元素。

在本教程中,我们将使用Vanilla JavaScript的HTML Drag and Drop API构建一个拖放示例,以使用事件处理器。

前提条件

要完成本教程,您将需要:

  • 支持 Drag and Drop API 的现代网页浏览器(Chrome 4+, Firefox 3.5+, Safari 3.1+, Edge 18+)。

步骤 1 – 创建项目和初始标记

我们的项目将包括两个类型的儿童元素的容器:

  • 孩子元素,你可以拖
  • 孩子元素,可能有元素落入它们

首先,打开终端窗口并创建一个新的项目目录:

1mkdir drag-and-drop-example

接下来,导航到该目录:

1cd drag-and-drop-example

然后,在该目录中创建一个index.html文件:

1nano index.html

接下来,为 HTML 网页添加 boilerplate 代码:

 1[label index.html]
 2<!DOCTYPE html>
 3<html>
 4  <head>
 5    <title>My Drag-and-Drop Example</title>
 6    <link rel="stylesheet" href="style.css" />
 7  </head>
 8  <body>
 9  </body>
10</html>

然后在<body>标签之间添加你的draggable项目和你的dropzone(降落目标):

 1[label index.html]
 2<div class="example-parent">
 3  <div class="example-origin">
 4    <div
 5      id="draggable-1"
 6      class="example-draggable"
 7    >
 8      draggable
 9    </div>
10  </div>
11
12  <div
13    class="example-dropzone"
14  >
15    dropzone
16  </div>
17</div>

保存并关闭文件,然后创建一个style.css文件:

1nano style.css

接下来,在我们的 index.html 文件中添加元素的样式:

 1[label style.css]
 2.example-parent {
 3  border: 2px solid #DFA612;
 4  color: black;
 5  display: flex;
 6  font-family: sans-serif;
 7  font-weight: bold;
 8}
 9
10.example-origin {
11  flex-basis: 100%;
12  flex-grow: 1;
13  padding: 10px;
14}
15
16.example-draggable {
17  background-color: #4AAE9B;
18  font-weight: normal;
19  margin-bottom: 10px;
20  margin-top: 10px;
21  padding: 10px;
22}
23
24.example-dropzone {
25  background-color: #6DB65B;
26  flex-basis: 100%;
27  flex-grow: 1;
28  padding: 10px;
29}

现在你可以在浏览器中查看index.html,并注意到这会产生一个draggable``<div>和一个dropzone``<div>

Screenshot of draggable and dropzone divs

接下来,我们将通过添加draggable属性来明确地使第一个<div>可拖动:

 1[label index.html]
 2<div class="example-parent">
 3  <div class="example-origin">
 4    <div
 5      id="draggable-1"
 6      class="example-draggable"
 7      draggable="true"
 8    >
 9      draggable
10    </div>
11  </div>
12
13  <div
14    class="example-dropzone"
15  >
16    dropzone
17  </div>
18</div>

保存并关闭文件。

最后,在浏览器中再次查看index.html。如果我们点击draggable``<div>,然后把它拖过屏幕,应该有视觉指示它在移动。

draggable属性的默认值为auto。这意味着该元素是否可拖放,将由您的浏览器的默认行为决定。

您现在有一个具有可拖放元素的HTML文件,我们将继续添加onevent处理器。

步骤 2 — 使用 JavaScript 处理拖放事件

目前,如果我们在拖动可拖动元素时释放鼠标,则不会发生任何事情. 要在 DOM 元素上触发拖动或下降的操作,我们需要使用 Drag and Drop API:

  • ondragstart:此事件处理器将附加到我们的 draggable 元素,并在发生 dragstart 事件时点燃
  • ondragover:当发生 dragover 事件时,此事件处理器将附加到我们的 dropzone 元素和火力
  • ondrop:此事件处理器也将附加到我们的 dropzone 元素和火力

<$>[注] **注:**共有八个事件处理器:ondrag,ondragend,ondragenter,ondragexit,ondragleave,ondragover,ondragstartondrop

首先,让我们在我们的index.html中引用一个新的script.js文件:

1[label index.html]
2<body>
3  ...
4  <script src="script.js"></script>
5</body>

接下来,创建一个新的script.js文件:

1nano script.js

DataTransfer对象将跟踪与当前拖动发生有关的信息。要更新我们在拖动和拖动时的元素,我们需要直接访问DataTransfer对象。

<$>[注] 注: DataTransfer 对象可以技术上跟踪同时拖拉的多个元素的信息。

dataTransfer对象的setData方法可用于为您当前拖动的元素设置拖动状态信息。

  • 声明第二参数 的格式的字符串 * 正在传输的实际数据

我们的目标是将我们的draggable元素移动到一个新的母元素. 我们需要能够选择我们的draggable元素具有独特的id

让我们重新浏览我们的script.js文件并创建一个新的函数来使用setData:

1[label script.js]
2function onDragStart(event) {
3  event
4    .dataTransfer
5    .setData('text/plain', event.target.id);
6}

<$>[注] **注:**据报道,Internet Explorer 9 至 11 使用文本/平面有问题。

为了更新被拖拉的项目的 CSS 风格,我们可以使用 DOM 事件再次访问其风格,并为当前目标设置我们想要的任何风格。

让我们添加到我们的函数并将背景颜色更改为黄色:

 1[label script.js]
 2function onDragStart(event) {
 3  event
 4    .dataTransfer
 5    .setData('text/plain', event.target.id);
 6
 7  event
 8    .currentTarget
 9    .style
10    .backgroundColor = 'yellow';
11}

<$>[注] **注:**您更改的任何风格都需要在下落时手动更新,如果您想要只有拖动的风格。

现在,我们有我们的JavaScript功能,用于拖拉开始时。

我们可以在index.html中的draggable元素中添加ondragstart:

 1[label index.html]
 2<div class="example-parent">
 3  <div class="example-origin">
 4    <div
 5      id="draggable-1"
 6      class="example-draggable"
 7      draggable="true"
 8      ondragstart="onDragStart(event);"
 9    >
10      draggable
11    </div>
12  </div>
13
14  <div class="example-dropzone">
15    dropzone
16  </div>
17</div>

查看您的浏览器中的index.html。如果你现在试图拖动您的项目,我们的功能中声明的样式将被应用:

Animated gif depicting an element getting dragged but not dropping

但是,当你释放你的点击时,不会发生任何事情。

在此序列中发射的下一个事件处理器是ondragover

浏览器中某些 DOM 元素的默认 drop 行为通常不接受 dropping. 这种行为会拦截我们正在试图实现的行为. 为了确保我们获得所需的 drop 行为,我们将应用preventDefault。

让我们重新浏览script.js文件并创建一个新的函数以使用preventDefault

1[label script.js]
2function onDragOver(event) {
3  event.preventDefault();
4}

现在,我们可以在index.html中的dropzone元素中添加ondragover:

 1[label index.html]
 2<div class="example-parent">
 3  <div class="example-origin">
 4    <div
 5      id="draggable-1"
 6      class="example-draggable"
 7      draggable="true"
 8      ondragstart="onDragStart(event);"
 9    >
10      draggable
11    </div>
12  </div>
13
14  <div
15    class="example-dropzone"
16    ondragover="onDragOver(event);"
17  >
18    dropzone
19  </div>
20</div>

在此时刻,我们还没有写代码来处理实际下降,在这个序列中发射的最后事件处理器是ondrop

让我们重新浏览我们的script.js文件并创建一个新的函数。

我们可以用dataTransfer对象的setData方法参考我们之前保存的数据,我们会使用dataTransfer对象的getData方法,我们设置的数据是id,所以这就是我们将返回的:

1[label script.js]
2function onDrop(event) {
3  const id = event
4    .dataTransfer
5    .getData('text');
6}

选择我们的draggable元素与我们获取的id:

1[label script.js]
2function onDrop(event) {
3  // ...
4
5  const draggableElement = document.getElementById(id);
6}

选择我们的dropzone元素:

1[label script.js]
2function onDrop(event) {
3  // ...
4
5  const dropzone = event.target;
6}

将我们的draggable元素附加到dropzone:

1[label script.js]
2function onDrop(event) {
3  // ...
4
5  dropzone.appendChild(draggableElement);
6}

重置我们的数据传输对象:

1[label script.js]
2function onDrop(event) {
3  // ...
4
5  event
6    .dataTransfer
7    .clearData();
8}

现在,我们可以在index.html中的dropzone元素中添加ondrop:

 1[label index.html]
 2<div class="example-parent">
 3  <div class="example-origin">
 4    <div
 5      id="draggable-1"
 6      class="example-draggable"
 7      draggable="true"
 8      ondragstart="onDragStart(event);"
 9    >
10      draggable
11    </div>
12  </div>
13
14  <div
15    class="example-dropzone"
16    ondragover="onDragOver(event);"
17    ondrop="onDrop(event);"
18  >
19    dropzone
20  </div>
21</div>

一旦完成,我们有一个完成的拖放功能. 在您的浏览器中查看index.html,然后将拖放元素拖到dropzone

Animated gif depicting an element getting dragged and dropped into a drop target

我们的示例处理了一个可拖放的项目和一个可拖放的目标的场景. 您可以拥有多个可拖放的项目,多个可拖放的目标,并与所有其他拖放 API 事件处理器进行定制。

步骤 3 – 用多个可拖动项目构建一个先进的示例

以下是您可以使用此 API 的另一个例子:一个可拖动任务列表,您可以将其从要做列移动到完成列。

Animated gif depicting multiple To-do tasks being dragged and dropped into a Done column

若要创建自己的任务列表,请将具有独特的id的更多可拖动元素添加到index.html:

 1[label index.html]
 2<div class="example-parent">
 3  <h1>To-do list</h1>
 4  <div class="example-origin">
 5    To-do
 6    <div
 7      id="draggable-1"
 8      class="example-draggable"
 9      draggable="true"
10      ondragstart="onDragStart(event);"
11    >
12      thing 1
13    </div>
14    <div
15      id="draggable-2"
16      class="example-draggable"
17      draggable="true"
18      ondragstart="onDragStart(event);"
19    >
20      thing 2
21    </div>
22    <div
23      id="draggable-3"
24      class="example-draggable"
25      draggable="true"
26      ondragstart="onDragStart(event);"
27    >
28      thing 3
29    </div>
30    <div
31      id="draggable-4"
32      class="example-draggable"
33      draggable="true"
34      ondragstart="onDragStart(event);"
35    >
36      thing 4
37    </div>
38  </div>
39
40  <div
41    class="example-dropzone"
42    ondragover="onDragOver(event);"
43    ondrop="onDrop(event);"
44  >
45    Done
46  </div>
47</div>

在浏览器中查看index.html,然后将To-do列中的项目拖到Done列,您已经创建了一个To-do应用程序并测试了其功能。

结论

在本文中,您创建了一个要做的应用程序来探索现代Web浏览器可用的拖放功能。

Drag and Drop API 提供了多种选项来自定义您的操作,而不是拖放。例如,您可以更新拖放的项目的 CSS 样式。

请记住,虽然许多网页浏览器支持此技术,但如果您的观众包括不支持此功能的设备(https://caniuse.com/#feat=dragndrop),则您可能无法依靠该技术。

要了解有关您可以放弃的 Drag and Drop API 的更多信息,请参阅它上的 MDN 的文档

Published At
Categories with 技术
Tagged with
comments powered by Disqus