首页与我联系

「手写原生代码专题」一个简单的列表拖拽示例(四)

By 前端达人
Published in 5-案例分享
October 04, 2022
1 min read
「手写原生代码专题」一个简单的列表拖拽示例(四)

大家好,在《原生手写代码实践 | 图片拖拽效果(一》这篇文章里我们已经学习了怎么拖拽图片,本篇文章我们继续学习拖拽,在几个单元格容器里拖拽列表,如下图所示: listdrag.gif这个需求比较常见,比如待办事项的相关应用,通过拖动的方式,更改事项的状态。在制作之前,我们来复习下和拖拽相关的事件。

一、拖拽相关的事件

拖拽(drag)指的是,用户在某个对象上按下鼠标键不放,拖动它到另一个位置,然后释放鼠标键,将该对象放在那里。

拖拉的对象有好几种,包括元素节点、图片、链接、选中的文字等等。在网页中,除了元素节点默认不可以拖拉,其他(图片、链接、选中的文字)都可以直接拖拉。为了让元素节点可拖拉,可以将该节点的draggable属性设为true

<div draggable="true">
  此区域可拖拉
</div>

上面代码的div区块,在网页中可以直接用鼠标拖动。松开鼠标键时,拖动效果就会消失,该区块依然在原来的位置。

draggable属性可用于任何元素节点,但是图片(<img>)和链接(<a>)不加这个属性,就可以拖拉。对于它们,用到这个属性的时候,往往是将其设为false,防止拖拉这两种元素。

注意,一旦某个元素节点的draggable属性设为true,就无法再用鼠标选中该节点内部的文字或子节点了。

当元素节点或选中的文本被拖拉时,就会持续触发拖拉事件,包括以下一些事件。

  • drag:拖拉过程中,在被拖拉的节点上持续触发(相隔几百毫秒)。
  • dragstart:用户开始拖拉时,在被拖拉的节点上触发,该事件的target属性是被拖拉的节点。通常应该在这个事件的监听函数中,指定拖拉的数据。
  • dragend:拖拉结束时(释放鼠标键或按下 ESC 键)在被拖拉的节点上触发,该事件的target属性是被拖拉的节点。它与dragstart事件,在同一个节点上触发。不管拖拉是否跨窗口,或者中途被取消,dragend事件总是会触发的。
  • dragenter:拖拉进入当前节点时,在当前节点上触发一次,该事件的target属性是当前节点。通常应该在这个事件的监听函数中,指定是否允许在当前节点放下(drop)拖拉的数据。如果当前节点没有该事件的监听函数,或者监听函数不执行任何操作,就意味着不允许在当前节点放下数据。在视觉上显示拖拉进入当前节点,也是在这个事件的监听函数中设置。
  • dragover:拖拉到当前节点上方时,在当前节点上持续触发(相隔几百毫秒),该事件的target属性是当前节点。该事件与dragenter事件的区别是,dragenter事件在进入该节点时触发,然后只要没有离开这个节点,dragover事件会持续触发。
  • dragleave:拖拉操作离开当前节点范围时,在当前节点上触发,该事件的target属性是当前节点。如果要在视觉上显示拖拉离开操作当前节点,就在这个事件的监听函数中设置。
  • drop:被拖拉的节点或选中的文本,释放到目标节点时,在目标节点上触发。注意,如果当前节点不允许drop,即使在该节点上方松开鼠标键,也不会触发该事件。如果用户按下 ESC 键,取消这个操作,也不会触发该事件。该事件的监听函数负责取出拖拉数据,并进行相关处理。

二、开始动手创建项目

复习完了基础的概念,我们开始动手开始练习,首先完成基础的 HTML 和 CSS 布局。

2.1、HTML 布局

我们先创建 4 个 DIV 容器,让被拖拽的列表元素,在这 4 个容器之间进行拖拽。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title> Simple Drag & Drop</title>
  </head>
  <body>
    <h1>Simple Drag & Drop</h1>
    <div class="lists-container">
      <div class="list">
        <div class="list-item" draggable="true">Item 1</div>
        <div class="list-item" draggable="true">Item 2</div>
        <div class="list-item" draggable="true">Item 3</div>
        <div class="list-item" draggable="true">Item 4</div>
        <div class="list-item" draggable="true">Item 5</div>
        <div class="list-item" draggable="true">Item 6</div>
        <div class="list-item" draggable="true">Item 7</div>
        <div class="list-item" draggable="true">Item 8</div>
      </div>
      <div class="list"></div>
      <div class="list"></div>
      <div class="list"></div>
    </div>
    <!-- ---------------------- -->
    <!-- JS File -->
    <script src="app.js"></script>
  </body>
</html>

从上面的代码,我们可以看出,在被拖动的元素 list-item 上添加 `draggable=“true”` ,这样才能进行拖动。

2.2、CSS 样式

接下来我们创建基础的 CSS 样式,代码比较简单,就不过多解释了

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

body {
  font-family: Arial, Helvetica, sans-serif;
  background-color: #26191b;
  color: #fff;
}

h1 {
  margin: 50px;
  text-align: center;
  font-size: 40px;
  font-weight: 100;
}

.lists-container {
  width: 1300px;
  height: 550px;
  margin: 0 auto;
  display: flex;
  /* overflow-x: scroll; */
}

.list {
  background-color: rgba(88, 65, 83, 0.5);

  display: flex;
  flex-direction: column;

  width: 100%;
  min-width: 200px;
  max-width: 300px;
  height: 100%;
  min-height: 150px;
  margin: 0 20px;
  transition: all 0.25s ease-in;
}

.list-item {
  background-color: hsl(300, 18%, 62%);
  padding: 15px 20px;
  text-align: center;
  margin: 8px 12px;
  cursor: pointer;
}

2.3、JS 文件

最后,也是项目的关键,我们创建 app.js 文件,完成核心的拖拽功能:

  • 通过 querySelectorAll 查找 lists DIV 容器和 listItems 被拖拽元素的DOM元素
  • 循环 listItems 为其添加 dragstartdragend 事件。
  • 循环 lists 容器,为其添加 dragoverdragenterdragleavedrop 事件,定义相关的样式行为和释放到目标节点的行为。

相关的 JS 代码如下:

const lists = document.querySelectorAll(".list");
const listItems = document.querySelectorAll(".list-item");

let draggedItem = null;

// https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API
for (let a = 0; a < listItems.length; a++) {
  const item = listItems[a];

  item.addEventListener("dragstart", function () {
    draggedItem = item;
    setTimeout(function () {
      item.style.display = "none";
    }, 50);
  });

  item.addEventListener("dragend", function () {
    setTimeout(() => {
      item.style.display = "block";
      draggedItem = null;
    }, 50);
  });

}

for (let b = 0; b < lists.length; b++) {
  const list = lists[b];

  list.addEventListener("dragover", function (e) {
    e.preventDefault();
  });

  list.addEventListener("dragenter", function (e) {
    e.preventDefault();
    list.style.backgroundColor = "rgba(255, 255, 255, 0.7)";
  });

  list.addEventListener("dragleave", function () {
    list.style.backgroundColor = "rgba(88, 65, 83, 0.5)";
  });

  list.addEventListener("drop", function () {
    list.append(draggedItem);
    list.style.backgroundColor = "rgba(88, 65, 83, 0.5)";
  });
}

结束

到这里本案例就介绍完了,你可以亲自动手尝试下,来加深对本案例的理解。

前端达人公众号.jpg

注:本文属于原创文章,版权属于「前端达人」公众号及 qianduandaren.com 所有,未经授权,谢绝一切形式的转载


Tags

javascript
Previous Article
「React Hooks 学习笔记」关于 useRef 的使用介绍(五)
前端达人

前端达人

专注前端知识分享

Table Of Contents

1
一、拖拽相关的事件
2
二、开始动手创建项目
3
结束

相关文章

「手写原生项目专题」一个带计时进度的在线答题应用(五)
October 07, 2022
1 min

前端站点

VUE官网React官网TypeScript官网

公众号:前端达人

前端达人公众号