实现效果

在这里插入图片描述

代码详情

<!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>
<body>
    <div class="list">
        <!-- draggable 属性必须设置,因为css设置了user-select为none  -->
        <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 draggable="true" class="list-item">6</div>
    </div>
</body>
</html>
<script>
    // 拖拽排序
    const list = document.querySelector('.list');
    const listItems = document.getElementsByClassName('list-item');  // 获取所有列表项 不要用 querySelectorAll因为它返回的是静态的NodeList,而getElementsByClassName返回的是动态的HTMLCollection

    let dragItem = null;
    let dragIndex = null; // 拖拽的元素索引
    let enterIndex = null; // 进入的元素索引

    list.addEventListener('dragstart', (e) => {
        setTimeout(() => {
            //  改成异步的,必须鼠标跟随的样式也变成move的样式
            e.target.classList.add('move');
            dragItem = e.target;
        }, 0);
    });

    list.addEventListener('dragenter', (e) => {
        e.preventDefault(); // 阻止默认行为 dragenter ,否则放开鼠标时可能会有问题
        if(e.target === list || e.target === dragItem) return; // 如果拖拽的元素是列表本身或者拖拽的元素本身,则不执行后续操作
        // const listItems = [...list.children] // 如果不在外部声明listItems 在这个时候必须重新获取listItems 因为listItems的顺序是动态变化的
        dragIndex = Array.from(listItems).indexOf(dragItem); // 拖拽的元素索引
        enterIndex = Array.from(listItems).indexOf(e.target); // 进入的元素索引
        if(enterIndex < dragIndex) {
            // 往上排
            console.log('向上排')
            list.insertBefore(dragItem, e.target);
        } else {
            // 往下排
            console.log('向下排')
            list.insertBefore(dragItem, e.target.nextSibling);
        }
    });

    list.addEventListener('dragend', (e) => {
        e.target.classList.remove('move');
        dragItem = null;
        dragIndex = null;
        enterIndex = null;
    })

</script>

<style>
    .list {
        display: flex;
        /* flex-direction 上下排列 */
        flex-direction: column; 
        gap: 10px;
    }

    .list-item {
        padding: 10px;
        background-color: #f0f0f0;
        cursor: grab;
        user-select: none; /* 防止拖拽时选中文字  但会导致默认的drag失效 */
    }

    .list-item.move {
        /* 被选中拖拽时的样式 */
        background: transparent;
        color: transparent;
        border: 1px dashed #ccc;
    }
</style>

代码知识要点

  1. querySelectorAll它返回的是静态的NodeList,而getElementsByClassName返回的是动态的
    如果list-item的顺序被改变了,querySelectorAll 不会是最新的list-item
  2. css设置了user-select为none 是防止拖拽时选中文字 但会导致默认的drag失效,所以为了drag能正常实现,list-item必须设置属性 draggable 为true
  3. dragstart 内使用异步的方式为被选中拖拽的盒子增加move样式,是为了防止,跟随鼠标的样式也变成了move的样式
  4. flex布局 只要改变 flex-direction 就可以将上下排列拖拽,变为横向的排列拖拽
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐