我们在实际开发中经常能遇见拖拽的运用场景,比如说拖拽排序、拖拽删除等,本文将以实现一个简单的课程表来进行拖拽API的简单应用,帮助大家复习一下一些基础知识。
相关拖拽事件
实现一个元素拖拽,我们只需要在HTML标签设置draggable
为true
js
<div class="left">
<div draggable="true" class="color1 item">语文</div>
<div draggable="true" class="color2 item">数学</div>
<div draggable="true" class="color3 item">英语</div>
<div draggable="true" class="color4 item">音乐</div>
<div draggable="true" class="color5 item">政治</div>
<div draggable="true" class="color6 item">历史</div>
<div draggable="true" class="color7 item">体育</div>
</div>
我们设置了拖拽属性,在拖动的过程中我们会触发很多事件
js
// 拖动开始
container.ondragstart = (e) => {
console.log('start', e.target)
}
// 拖动覆盖
container.ondragover = (e) => {
console.log('over', e.target)
}
// 拖动进入
container.ondragenter = (e) => {
console.log('enter', e.target)
}
// 拖动结束
container.ondrop = (e) => {
// 一般div、td是不允许有元素置于他们上面,在ondragover设置阻止冒泡
console.log('drop', e.target)
}
如上,我们在这个应用主要用到了这几个拖拽事件,其中要特别注意的是ondrop
事件,因为很多的HTML
标签是不允许有其他元素覆盖在他们上面的,我们在案例中最外层用了div
标签,所以必须要设置阻止冒泡才能让该事件生效
设置拖拽鼠标样式
如效果图所演示,我们在新增课程的时候,鼠标呈现的是一个加号的状态,在移除时又是一个简单的鼠标样式。这里我们是通过dataset
和ondragstart
设置相关属性来进行动态实现的
js
<div class="left">
<div data-effect="copy" draggable="true" class="color1 item">语文</div>
<div data-effect="copy" draggable="true" class="color2 item">数学</div>
<div data-effect="copy" draggable="true" class="color3 item">英语</div>
<div data-effect="copy" draggable="true" class="color4 item">音乐</div>
<div data-effect="copy" draggable="true" class="color5 item">政治</div>
<div data-effect="copy" draggable="true" class="color6 item">历史</div>
<div data-effect="copy" draggable="true" class="color7 item">体育</div>
</div>
js
container.ondragstart = (e) => {
// 设置拖拽鼠标样式 默认值为move
e.dataTransfer.effectAllowed = e.target.dataset.effect
}
设置拖拽背景色
依旧根据设置的datakey
,并检索父级,通过ondragenter
事件动态插入class
,实现背景色的显示
js
<div class="left" data-drop="move">
<div data-effect="copy" draggable="true" class="color1 item">语文</div>
<div data-effect="copy" draggable="true" class="color2 item">数学</div>
<div data-effect="copy" draggable="true" class="color3 item">英语</div>
<div data-effect="copy" draggable="true" class="color4 item">音乐</div>
<div data-effect="copy" draggable="true" class="color5 item">政治</div>
<div data-effect="copy" draggable="true" class="color6 item">历史</div>
<div data-effect="copy" draggable="true" class="color7 item">体育</div>
</div>
<tr>
<th rowspan="4" class="span">上午</th>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
</tr>
js
function getDropNode(node){
while(node){
if(node?.dataset?.drop){
return node
}
node = node.parentNode
}
}
function clearDropStyle(){
const dropNodes = document.querySelectorAll('.drop-over')
dropNodes.forEach((node) => {
node.classList.remove('drop-over')
})
}
container.ondragenter = (e) => {
clearDropStyle()
const dropNode = getDropNode(e.target)
if(!dropNode){
return
}
if( e.dataTransfer.effectAllowed === dropNode?.dataset?.drop){
dropNode.classList.add('drop-over')
}
}
实现新增删除
根据一开始的设想,我们是新增了dataset
进行同类别的有效拖拽,依旧进行比较,根据情况新增、删除节点
js
let source;
container.ondragstart = (e) => {
// 设置拖拽鼠标样式
e.dataTransfer.effectAllowed = e.target.dataset.effect
source = e.target
}
container.ondrop = (e) => {
// 一般div、td是不允许有元素置于他们上面,在ondragover设置组织冒泡
console.log('drop', e.target)
clearDropStyle()
const dropNode = getDropNode(e.target)
if(!dropNode){
return
}
if(e.dataTransfer.effectAllowed !== dropNode.dataset.drop){
return
}
if(dropNode.dataset.drop === 'copy'){
dropNode.innerHTML = ''
const cloned = source.cloneNode(true)
cloned.dataset.effect = 'move'
dropNode.appendChild(cloned)
}else{
source.remove()
}
}
我们在ondrop
是不能拿到拖拽的节点的,设置一个全局变量,在ondragstart
中保存节点,同时在复制完节点后要将其dataset-effect
改成move