拖拽API的简单应用

我们在实际开发中经常能遇见拖拽的运用场景,比如说拖拽排序、拖拽删除等,本文将以实现一个简单的课程表来进行拖拽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

相关推荐
程序员Sunday2 小时前
JavaScript 事件循环面试题,宏任务与微任务怎么执行|Sunday面试指南
开发语言·javascript·面试·校招·事件循环·程序员sunday
Setsuna_F_Seiei2 小时前
前端转型 Agent 开发 06 之 Agent Memory 记忆系统(让 Agent 更智能,更懂你)
前端·agent·ai编程
zhangzeyuaaa3 小时前
Ruby 多线程、GVL(GIL)与 Mutex 完全指南
开发语言·前端·ruby
默_笙4 小时前
🌊 向量库和 ES 都查不出"关系",我只好给奶茶建了一张人脉网
前端·javascript
优选资讯4 小时前
标签打印软件怎么对接 Excel 数据
前端·excel
思无邪664 小时前
用 AI 做 JS 逆向:从抓包到复现的完整方法论
开发语言·javascript·人工智能
一个风轻云淡5 小时前
GCC 和 GDB命令简单解读
java·linux·前端
u0111026756 小时前
图片处理接口如何统一错误信息 前端提示与后端错误码设计
前端·状态模式
福兮说6 小时前
浏览器里把 iPhone 的 HEIC 转成 JPG:Chrome 解不开、转完大了七成、拍摄时间全丢,六个坑实测
前端·javascript·图像处理·chrome·ios·iphone·heic
libokaifa6 小时前
把语音模型塞进手机:sherpa-onnx 在 Android 上的 ASR / TTS
前端