JS实现拖拽元素交换位置

  • Post author:
  • Post category:其他


源码:

js-essays/draggable



基本效果展示:

在这里插入图片描述



基本思路:

使元素可以被拖拽(利用 draggable 属性, 注意:链接和图片默认是可拖拽的)

拖拽时,通过被拖拽节点和其他节点的drag事件交互,来切换两个节点的位置(非唯一方法)

添加用户拖拽交互效果



用到的方法:

ondrag 事件在元素或者选取的文本被拖动时触发。

在拖动目标上触发(源目标元素):

ondragstart – 用户开始拖动元素

ondrag – 元素正在被拖动

ondragend – 用户结束元素拖动

释放目标时触发的事件:

ondragenter – 当被拖动的对象进入其容器范围内时触发

ondragover – 当被拖动的对象在另一对象容器范围内拖动时触发

ondragleave – 当被拖动的对象离开其容器范围内时触发

ondrop – 在一个拖动过程中,释放鼠标键时触发

注意: 在拖动元素时,每隔 350 毫秒会触发 ondrag 事件。



基本实现(无交互):
function dragHandler() {
  // 用来存取被拖拽的节点
  let draggedNode = null
  // 获取可拖拽节点
  const dragNodes = document.querySelectorAll('div[draggable="true"]')
  // 给可拖拽节点绑定相关事件
  dragNodes.forEach(item => {
    item.ondragstart = () => {
      draggedNode = item
    }
    // 默认情况下,数据/元素不能在其他元素中被拖放,也就是会阻止你做drop操作,所以取消其默认行为
    item.ondragover = e => {
      e.preventDefault()
    }
    // 被拖拽的节点,被释放后进行节点替换
    item.ondrop = e => {
      if (draggedNode !== null && draggedNode !== item) {
        const temp = document.createElement('div')
        const dragBox = document.getElementById('drag-box')
        dragBox.replaceChild(temp, e.target)
        dragBox.replaceChild(e.target, draggedNode)
        dragBox.replaceChild(draggedNode, temp)
      }
    }
  })
}
dragHandler()



有交互效果:
function dragHandler() {
  // 用来存取被拖拽的节点
  let draggedNode = null
  // 存放被拖拽节点的背景
  let draggedNodeBg = null
  // 存放被拖拽节点进入的容器(节点) 的旧背景
  let dragEnterNodeBg = null
  // 获取可拖拽节点
  const dragNodes = document.querySelectorAll('div[draggable="true"]')
  // 给可拖拽节点绑定事件
  dragNodes.forEach(item => {
    item.ondragstart = () => {
      draggedNode = item
      // 拖拽开始,设置背景
      draggedNodeBg = getComputedStyle(item).background
      item.style.background = '#bbb'
    }
    // 默认情况下,数据/元素不能在其他元素中被拖放,也就是会阻止你做drop操作,所以取消其默认行为
    item.ondragover = e => {
      e.preventDefault()
    }
    // 被拖拽的节点,被释放后进行节点替换
    item.ondrop = e => {
      if (dragEnterNodeBg) {
        // 拖拽被释放,恢复目标节点背景
        e.target.style.background = dragEnterNodeBg
      }
      if (draggedNode !== null && draggedNode !== item) {
        const temp = document.createElement('div')
        const dragBox = document.getElementById('drag-box')
        dragBox.replaceChild(temp, e.target)
        dragBox.replaceChild(e.target, draggedNode)
        dragBox.replaceChild(draggedNode, temp)
      }
    }
    // 样式交互
    item.ondragend = () => {
      item.style.background = draggedNodeBg
    }
    item.ondragenter = () => {
      if (item !== draggedNode) {
        dragEnterNodeBg = getComputedStyle(item).background
        item.style.background = 'darkcyan'
      }
    }
    item.ondragleave = () => {
      if (dragEnterNodeBg && item !== draggedNode) {
        item.style.background = dragEnterNodeBg
      }
    }
  })
}
dragHandler()