HTML5实现了原生拖动的接口,因此在实现拖拽功能时,可以直接使用该方法。下面用一个例子学习其用法。
案例背景:
实现ol
列表的拖拽可排序功能。
实现过程:
- 拟实现一个类似于下面的
ol
列表。该列表需要有可拖拽调整顺序的功能。给标签加入draggable
属性,标签即赋予拖拽功能。li
标签在JS中用数据动态写入,方便拖拽时对数据进行操作,从而控制列表顺序。
<ol>
<!-- <li draggable="true" order=0>apple</li>
<li draggable="true" order=0>pear</li>
<li draggable="true" order=0>peach</li>-->
</ol>
li
相应的css代码如下
li{
border-bottom:1px solid #ccc;
width:100px;
margin-bottom:5px;
}
- JS动态写入标签
JS
中加入以下方法生成li
标签,给每个li
标签加入draggable
属性使其可拖拽,以及order
属性标记索引值。
let data = ['苹果', '香蕉', '梨','草莓']
initDom=(data)=>{
let ol = document.getElementsByTagName('ol')[0]
ol.innerHTML=""
data.map((item,index)=>{
let newElement = document.createElement('li')
newElement.setAttribute('draggable', true)
newElement.setAttribute('order', index)
let textNode = document.createTextNode(item)
newElement.appendChild(textNode)
ol.appendChild(newElement)
})
}
initDom(data)
- 拖动事件处理:
拖动事件主要由以下几个事件组成:
-
dragstart
: 开始拖拽的时候触发的事件,作用于被拖拽的元素。 -
dragenter
: 拖拽元素进入目标元素时触发,作用于目标元素。 -
dragover
:拖拽元素在目标元素上方移动时触发,作用于目标元素。 -
dragleave
: 拖拽元素离开目标元素时触发,作用于目标元素。 -
drop
: 鼠标放开拖拽元素时触发在目标元素上的事件。 -
dragend
: 拖拽结束后,作用于被拖拽元素上的事件。
上述例子中,利用事件冒泡在外层ol
标签上加入拖拽事件,不用加在每个li
标签上。
dragstart
:
在开始拖拽时,希望被拖拽元素加入透明度的样式以进行标记。dataTransfer
可以在拖拽过程中传递数据。此处将索引值传递过去,方便最后进行重排序。
let ol = document.getElementsByTagName('ol')[0];
ol.ondragstart=(event)=>{
event.target.style.opacity = 0.4;
const dragIndex = event.target.attributes.order.nodeValue
event.dataTransfer.setData("text/dragIndex",dragIndex);
}
dragover
:
在拖动过程中,如果在目标元素上方移动时,给目标元素加一个样式进行标记。
ol.ondragover = (event)=>{
//默认拒绝接受任何被拖放的元素,取消默认
event.preventDefault();
if(event.target.nodeName.toLowerCase()==='li'){
event.target.style.borderBottom = '1px solid red'
}
}
dragleave
:
当被拖动元素离开目标元素时,需要恢复目标元素的样式。
ol.ondragleave = (event)=>{
if(event.target.nodeName.toLowerCase()==='li'){
event.target.style.borderBottom = '1px solid #ccc'
}
}
dragend
:
当拖动结束时,恢复被拖拽元素的样式。
ol.ondragend = (event)=>{
event.target.style.opacity = 1;
}
dragdrop
:
放下拖拽元素时,需要处理数据逻辑,以更改DOM结构,交换元素。
ol.ondrop = (event)=>{
//浏览器默认元素会阻止drop,所以取消默认
event.preventDefault();
if(event.target.nodeName.toLowerCase()==='li'){
const dropIndex = Number(event.target.attributes.order.nodeValue)
const dragIndex = Number(event.dataTransfer.getData("text/dragIndex"))
const dragData = data[dragIndex]
const dropData = data[dropIndex]
data.splice(dropIndex, 1, dragData)
data.splice(dragIndex, 1, dropData)
initDom(data)
}
}
注意点:
-
dragover
和drop
事件需要加入event.preventDefault()
,否则该事件会不起作用。 - 拖拽过程中数据的传递可通过
event.dataTransfer.setData("数据类型名称",数据)
和event.dataTransfer.getData("数据类型名称")
实现。 - 拖拽结束时的数据交换逻辑需要写在
drop
中而不是dragend
,dragend
作用的元素是被拖拽的元素。
网友评论