js 实现任意多列子项互相拖放功能

2024-07-15

一、效果演示

二、代码实现

完整代码如下,理论上无论 html 是一列还是一百列,js 代码是不需要改动的。

<style>
    .wrapper {
        display: flex;
        gap: 20px;

        .left-item,
        .middle-item,
        .right-item {
            width: 200px;
            height: 50px;
            text-align: center;
            line-height: 50px;
        }

        .left-list,
        .middle-list,
        .right-list {
            display: flex;
            flex-direction: column;
            gap: 10px;
            border: 1px solid #ccc;
            padding: 4px;
            height: fit-content;
        }

        .left-item {
            background-color: aqua;
        }

        .middle-item {
            background-color:bisque;
        }

        .right-item {
            background-color: thistle;
        }
    }
</style>

<div class="wrapper">
    <div class="left-list">
        <div class="left-item" draggable="true">item1</div>
        <div class="left-item" draggable="true">item2</div>
        <div class="left-item" draggable="true">item3</div>
    </div>
    <div class="middle-list">
        <div class="middle-item" draggable="true">item1</div>
        <div class="middle-item" draggable="true">item2</div>
        <div class="middle-item" draggable="true">item3</div>
    </div>
    <div class="right-list">
        <div class="right-item" draggable="true">item1</div>
        <div class="right-item" draggable="true">item2</div>
        <div class="right-item" draggable="true">item3</div>
    </div>
</div>

<script>
    const wrapperEl = document.querySelector('.wrapper')

    let sourceEl = null

    const onDragStart = e => {
        // 记录拖动的元素,称为源元素
        sourceEl = e.target
    }

    const onDragOver = e => {
        // 阻止 dragover 默认动画,可以尝试把这行代码去掉会发现拖动动画很奇怪
        e.preventDefault()

        const targetEl = e.target
        // 目标元素与源元素相同,或者目标元素 draggable 属性不为 true,说明不可拖动,直接返回
        if (targetEl === sourceEl || !targetEl.draggable) {
            return
        }

        // 计算目标元素中间点 y 坐标
        const targetRect = targetEl.getBoundingClientRect()
        const targetMiddleY = targetRect.top + targetRect.height / 2
        // 鼠标当前位置 y 坐标
        const clientY = e.clientY

        // 鼠标当前位置在目标元素中间点上方,移动到当前元素上方
        if (clientY < targetMiddleY) {
            targetEl.parentNode.insertBefore(sourceEl, targetEl)
        }
        // 鼠标当前位置在目标元素中间点下方,移动到当前元素下方
        else {
            targetEl.parentNode.insertBefore(sourceEl, targetEl.nextSibling)
        }
    }

    wrapperEl.addEventListener('dragstart', onDragStart)
    wrapperEl.addEventListener('dragover', onDragOver)
</script>

返回首页

本文总阅读量  次
总访问量: 
总访客量: