实现列表拖拽排序功能。全网最超详细の注释讲解,看完必会!

1,215 阅读3分钟

前言

列表拖拽排序是一个常见的需求,实现的方式很多,接下来让我们使用HTML5的一个新特性draggable属性实现这个功能。

Main

需求思路:

  1. 获取所有 li 元素。
  2. 创建变量 draggedItem 用于存储被拖拽的元素。
  3. 遍历所有 li元素,给每个元素添加三个事件监听器:
    • dragstart 事件:当元素开始被拖拽时,将该元素存储到 draggedItem 中,并将该元素隐藏。
    • dragover 事件:当元素被拖拽经过另一个元素时,阻止默认行为,判断该元素是否为合法的拖放目标(不是被拖拽的元素本身,且为 li 元素),计算目标元素的位置,根据拖拽的位置插入被拖拽的元素到目标元素的前面或后面。
    • dragend 事件:当元素拖拽结束时,将元素显示出来,并将 draggedItem 设为 null

Tip:当我们得到一个需求的时候,可以先列出编码的思路,然后再去code,就会思路清晰哝!

然后就要开始编码了哝。

微信图片_20230402195919.jpg

  <ul class="sortable-list">
        <li draggable="true" id="item1">Item 1</li>
        <li draggable="true" id="item2">Item 2</li>
        <li draggable="true" id="item3">Item 3</li>
        <li draggable="true" id="item4">Item 4</li>
        <li draggable="true" id="item5">Item 5</li>
        <li draggable="true" id="item6">Item 6</li>
        <li draggable="true" id="item7">Item 7</li>
        <li draggable="true" id="item8">Item 8</li>
        <li draggable="true" id="item9">Item 9</li>
        <li draggable="true" id="item10">Item 10</li>
        <li draggable="true" id="item11">Item 11</li>
        <li draggable="true" id="item12">Item 12</li>
    </ul>

CSS 部分定义了可拖动列表项的样式:

       .sortable-list {
            list-style: none;
            /* 去除列表默认的样式 */
            margin: 0;
            /* 去除默认的外边距 */
            padding: 0;
            /* 去除默认的内边距 */
        }

        li {
            background-color: #f2f2f2;
            /* 设置背景颜色 */
            border: 1px solid #ccc;
            /* 设置边框 */
            cursor: move;
            /* 设置鼠标样式为移动 */
            margin-bottom: 5px;
            /* 设置下边距 */
            padding: 10px;
            /* 设置内边距 */
            transition: all 0.2s ease-in-out;
            /* 设置过渡动画效果 */
        }

        li:hover {
            background-color: #e0e0e0;
            /* 当鼠标悬停在元素上时,改变背景颜色 */
        }

        li:active {
            background-color: #ccc;
            /* 当元素被按下时,改变背景颜色 */
        }

        li.placeholder {
            background-color: #ddd;
            /* 占位符元素的背景颜色 */
            opacity: 0.5;
            /* 占位符元素的透明度 */
        }

JavaScript部分定义拖拽排序逻辑:

   // 选择所有 li 元素
        const items = document.querySelectorAll('li');
        // 创建一个变量来存储被拖动的元素
        let draggedItem = null;
        // 遍历每个 li 元素并为其添加事件监听器
        for (let i = 0; i < items.length; i++) {
            const item = items[i];
            // 当拖动开始时触发
            item.addEventListener('dragstart', function () {
                // 将当前被拖动的元素赋值给变量
                draggedItem = item;
                // 使用 setTimeout 方法来确保当前被拖动的元素在开始拖动时被隐藏
                setTimeout(function () {
                    item.style.display = 'none';
                }, 0);
            });
            // 当拖动元素在 li 元素上方时触发
            item.addEventListener('dragover', function (e) {
                e.preventDefault();
                // 确保目标元素不是被拖动的元素本身,并且目标元素是 li 元素
                if (e.target !== draggedItem && e.target.nodeName === 'LI') {
                    // 获取目标元素的位置信息
                    const bounding = e.target.getBoundingClientRect();
                    // 计算目标元素的中心点位置
                    const offset = bounding.y + bounding.height / 2;
                    // 如果当前鼠标位置在目标元素的上半部分,则将被拖动的元素插入到目标元素之前
                    if (e.clientY < offset) {
                        e.target.parentNode.insertBefore(draggedItem, e.target);
                        // 如果当前鼠标位置在目标元素的下半部分,则将被拖动的元素插入到目标元素之后
                    } else {
                        e.target.parentNode.insertBefore(draggedItem, e.target.nextSibling);
                    }
                }
            });
            // 当拖动结束时触发
            item.addEventListener('dragend', function () {
                // 将被拖动的元素重新显示出来
                draggedItem.style.display = 'block';
                // 清除对被拖动元素的引用
                draggedItem = null;
            });
        }

效果展示 gif效果不太好

image_0.9402403585609604.gif

结束语:如果对您有帮助!点个赞,加个关注吧,有问题评论区留言交流哦!