完整代码如下,理论上无论 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>
↶ 返回首页