描述:使用h5新增的拖拽属性draggable实现多个列表各自拖拽排序功能,多个列表之间互不影响。拖拽过程元素实时更新,交换位置。松开鼠标后得到拖拽前索引和拖拽后索引,根据索引对数据源进行更新。
使用的事件介绍
onmousedown:鼠标按钮在元素上按下时触发
onmouseup:在元素上松开鼠标按钮时触发
ondragenter:元素被 拖拽到 绑定该事件的元素范围内就触发
ondragover:鼠标移动时 , 元素在绑定该事件的元素范围内就会触发(非常频繁 , 影响性能 , 所以一般会阻止其默认事件e.preventDefault(),添加该事件可以给鼠标小手携带拖拽图标)
ondragend:拖拽结束
html
<p class="title">列表一</p>
<ul>
<li>
<span class="drag">1</span><span>文本一</span>
</li>
<li>
<span class="drag">2</span><span>文本二</span>
</li>
<li>
<span class="drag">3</span><span>文本三</span>
</li>
<li>
<span class="drag">4</span><span>文本四</span>
</li>
<li>
<span class="drag">5</span><span>文本五</span>
</li>
<li>
<span class="drag">6</span><span>文本六</span>
</li>
<li>
<span class="drag">7</span><span>文本七</span>
</li>
<li>
<span class="drag">8</span><span>文本八</span>
</li>
<li>
<span class="drag">9</span><span>文本九</span>
</li>
</ul>
<p class="title">列表二</p>
<ul>无</ul>
<p class="title">列表三</p>
<ul>
<li>
<span class="drag">1</span><span>aaa</span>
</li>
<li>
<span class="drag">2</span><span>bbb</span>
</li>
<li>
<span class="drag">3</span><span>ccc</span>
</li>
</ul>
<p class="title">列表四</p>
<ul>
<li>
<span>1</span><span>111</span>
</li>
<li>
<span>2</span><span>222</span>
</li>
<li>
<span>3</span><span>333</span>
</li>
<li>
<span>1</span><span>444</span>
</li>
<li>
<span>2</span><span>555</span>
</li>
<li>
<span>3</span><span>666</span>
</li>
</ul>
css
<style>
* {
padding: 0;
margin: 0;
}
ul {
border: 1px solid hotpink;
padding: 10px;
margin: 20px;
}
li {
width: 300px;
height: 20px;
border: 1px solid #333;
border-radius: 2px;
margin: 10px 20px;
list-style: none;
/* text-align: center; */
display: flex;
}
.drag {
cursor: pointer;
}
span:nth-child(1) {
flex: .4;
background-color: skyblue;
}
span {
text-align: center;
}
</style>
js
<script>
// 为需要拖拽的表格添加事件
let uls = document.querySelectorAll('ul')
// 当前拖拽所在ul的索引
let dragUlIndex = null
// 当前拖拽dom
let dragLiTagger = null
// 当前拖拽dom的索引
let dragLiIndex = null
// 被拖入dom的索引
let enterLiIndex = null
for (let ulIndex = 0; ulIndex < uls.length; ulIndex++) {
let ulItem = uls[ulIndex];
let lis = ulItem.children
// 列表为空 || li标签不需要拖拽效果的不处理
if (lis.length === 0 || !ulItem.children[0].children[0].className.includes('drag')) continue;
// console.log(`第${ulIndex + 1}个表格可拖拽`);
fn(ulItem, ulIndex, lis)
}
function fn(ulItem, ulIndex, lis) {
for (let liIndex = 0; liIndex < lis.length; liIndex++) {
let li = lis[liIndex]
let dragDom = lis[liIndex].children[0]
// 只对索引列添加拖拽效果
dragDom.onmousedown = function () {
li.setAttribute('draggable', true)
dragUlIndex = ulIndex
dragLiTagger = li
// 存储当前拖拽列索引
dragLiIndex = Array.from(lis).indexOf(dragLiTagger)
}
dragDom.onmouseup = function () {
li.setAttribute('draggable', false)
}
li.ondragenter = function () {
// 拖拽到其他列表不处理
if (dragUlIndex !== ulIndex) return
// 存储当前拖拽dom的索引和被拖入dom的索引
let dragLiIndex = Array.from(lis).indexOf(dragLiTagger)
enterLiIndex = Array.from(lis).indexOf(li)
// 在当前dom上反复左右拖拽不处理
if (dragLiIndex === enterLiIndex) return
// console.log('拖拽在同一个ul中')
// console.log({
// '拖拽元素': dragLiTagger,
// '拖拽元素索引': dragLiIndex,
// '被拖入元素': li,
// '被拖入元素索引': enterLiIndex
// })
if (dragLiIndex < enterLiIndex) {
// 前面的dom拖到后面
ulItem.insertBefore(dragLiTagger, li.nextElementSibling)
} else if (dragLiIndex > enterLiIndex) {
// 后面的dom拖到前面
ulItem.insertBefore(dragLiTagger, li)
}
}
li.ondragover = function (e) {
e.preventDefault()
}
li.ondragend = function () {
dragLiTagger.setAttribute('draggable', false)
if (enterLiIndex === null || dragLiIndex === enterLiIndex) return
// 有拖拽变化
console.log({
'拖拽ul': ulIndex,
'拖拽前索引': dragLiIndex,
'拖拽后索引': enterLiIndex
})
console.log('可更新数据')
// 根据拖拽前后的索引, 对数据进行更新
enterLiIndex = null
}
}
}
</script>