原生手动排序

原生手动排序

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <style>
    .content-list {
      display: flex;
      flex-direction: column;
      gap: 8px;
    }

    .list-item {
      cursor: pointer;
      width: 50%;
      border: 1px solid red;
      background-color: aqua;
    }

    .moving {
      background-color: unset;
      border: 1px solid;
      border-style: dashed;
    }
  </style>

  <body>
    <div class="content-list">
      <div draggable="true" class="list-item">1</div>
      <div draggable="true" class="list-item">2</div>
      <div draggable="true" class="list-item">3</div>
      <div draggable="true" class="list-item">4</div>
      <div draggable="true" class="list-item">5</div>
    </div>
  </body>
  <script>
    let dom = document.querySelector(".content-list");
    let currentDom;
    dom.ondragstart = (e) => {
      setTimeout(() => {
        e.target.classList.add("moving");
      }, 0);
      currentDom = e.target;
    };
    dom.ondragover = (e) => {
      e.preventDefault();
    };
    dom.ondragenter = (e) => {
      e.preventDefault();
      if (e.target !== dom && e.target !== currentDom) {
        console.log(e.target);
      }
      const children = Array.from(dom.children);
      const currentIndex = children.findIndex((item) => item === currentDom);
      const dropIndex = children.findIndex((item) => item === e.target);
      if (currentIndex > dropIndex) {
        dom.insertBefore(currentDom, e.target);
      } else {
        dom.insertBefore(currentDom, e.target.nextElementSibling);
      }
      console.log(children, currentIndex);
    };
    dom.ondragend = (e) => {
      setTimeout(() => {
        e.target.classList.remove("moving");
      }, 0);
    };
  </script>
</html>

拖放事件

  1. dragstart: 当用户开始拖动一个元素或选中的文本时触发。
  2. dragover: 当某被拖动的元素或选中的文本在另一个元素上方时触发。
  3. dragenter: 当某被拖动的元素或选中的文本进入有效的放置目标时触发。
  4. dragleave: 当某被拖动的元素或选中的文本离开有效的放置目标时触发。
  5. drag: 当元素或选中的文本被拖动时触发。
  6. drop: 当被拖动的元素或选中的文本在放置目标上被释放时触发。
  7. dragend: 当拖动操作结束时(释放鼠标按钮或按下 ESC 键)触发。

实现思路和代码解读

  1. 设置元素可拖动:为了使元素可拖动,你需要设置 draggable="true"属性。在你的代码中,每个.list-item 都设置了这个属性。

  2. 处理 dragstart 事件:当拖动开始时,一个 dragstart 事件被触发。在你的事件处理函数里,你使用 setTimeout 设置了一个微任务,延迟将拖动元素的类名设置为.moving,从而使其变为虚线框(类似占位符的效果)。同时,你保存了当前拖动的元素,以便之后使用。

  3. 处理 dragover 事件:dragover 事件在元素被拖动到另一个元素上方时触发。为了让元素能够放置,你需要阻止默认行为(默认情况下,数据/元素不能被放置到其他元素上)。

  4. 处理 dragenter 事件:dragenter 事件在拖动的元素进入放置目标时触发。在事件处理函数中,你检查了进入的目标,如果它既不是容器本身也不是当前拖动的元素,你会计算当前拖动元素和进入元素的索引,然后根据索引将当前拖动元素放置在适当的位置(前面或后面)。

  5. 处理 dragend 事件:dragend 事件在拖动结束时触发,无论操作成功与否。在事件处理函数中,你移除了.moving 类,恢复元素的原始样式。

关键点

  1. e.preventDefault(): 在 dragover 和 dragenter 事件中使用,是为了允许将元素放置到其他元素上(改变默认不允许放置的行为)。

  2. setTimeout(..., 0): 通过将操作推迟到调用栈清空之后,避免了在拖动过程中对元素样式的立即更改,这可以防止出现不必要的渲染问题。

  3. insertBefore: 这个 DOM 操作方法用来在指定的子节点前插入一个新的子节点,如果参照节点为 null,则插入到子节点列表的末尾。

  4. 整体上,你的代码利用了 HTML5 拖放 API 执行元素的垂直排序。用户通过拖放操作可以重新安排.list-item 元素的顺序,而代码则负责处理所有必要的事件来使这些操作可能。

posted @ 2024-03-28 10:42  郭杰前端开发  阅读(1)  评论(0编辑  收藏  举报
## 希望内容对你有帮助,如果有错误请联系我 q: 1911509826,感谢支持