前端拖拽组件实践

淮城一只猫 编程技术
阅读量 0 评论量 0

前言

这几年做的可视化项目越来越多,这需要前端的 dragdrop 元素能力(下文简称 dnd),dnd 能力极大提高前端交互能力。然而在开发项目期间很少去了解其运行原理,这段时间趁着空余时间算是系统学习下前端 dnd 事件能力吧。

上面讲述到的 dragdrop 是前端元素上的事件,除了监听这俩个事件之外,还需要对元素进行拖拽支持:

<style>
  .drag {
    position: relative;
    width: 100px;
    height: 100px;
    color: #fff;
    text-align: center;
    line-height: 100px;
    background: #ccc;
    user-select: none;
    cursor: grab;
  }
  .drop {
    position: absolute;
    top: 0;
    left: 200px;
    width: 400px;
    height: 400px;
    background: #eee;
  }
</style>

<div class="app-wrapper">
  <div class="drag-wrapper">
    <div draggable="true" id="dragger" class="drag">
      拖动元素
    </div>
  </div>
  <div class="drop-wrapper">
    <div class="drop">
      放置区域
    </div>
  </div>
</div>

只需要在需要拖拽的元素上添加 draggable 属性,该属性的值是布尔值:

  • true 表示元素可以被拖动
  • false 表示元素不可以被拖动

简单的拖拽例子就这样出来了,但还是远远不够,需要监听对应的事件来满足某些需求。

事件

dnd 事件主要分为拖拽和放置俩大事件类型。

拖拽事件如下:

  • dragstart 开始拖拽元素返回回调事件
  • drag 拖拽期间一定频率返回回调事件
  • dragend 拖拽结束返回回调事件

放置事件如下:

  • dragenter 当拖拽元素拖到可放置元素时候返回回调事件
  • dragover 当拖拽元素拖到可放置元素期间一定频率返回回调事件
  • dragleave 当拖拽元素离开可放置元素时候返回回调事件
  • drop 当拖拽元素在放置元素放置返回回调事件

拖拽数据

上面列出都会有 DragEvent 回调事件,回调事件中有个 dataTransfer 属性,关于他的介绍如下:

DataTransfer 对象用于保存拖动并放下(drag and drop)过程中的数据。它可以保存一项或多项数据,这些数据项可以是一种或者多种数据类型。

这个属性主要包含:

  • dropEffect
  • effectAllowed
  • files 包含数据传输中可用的所有本地文件的列表。
  • items(只读)
  • types(只读)

dropEffect 属性拖放操作的视觉效果:

  • none
  • copy
  • link
  • move

effectAllowed 用来指定当元素被拖放式所允许的视觉效果:

  • none
  • move
  • copy
  • link
  • copyMove
  • copyLink
  • linkMove
  • all
element.addEventListener('dragenter', event => {
  event.dataTrasfer.dropEffect = 'move'
})

下面的例子可以利用 dataTransfer 属性将拖拽的元素在放置元素上起到放置效果作用:

<style>
  body {
    background-color: #F1C40F;
    font-family: "Courier New";
  }

  .container {
    display: grid;
    grid-template-columns: 33% 33% 33%;
  }

  .draggable, .droptarget {
    border: 20px solid white;
    margin: 30px;
    padding: 30px;
    text-align: center;
    color: white;
    font-size: 2rem;
  }

  .one {
    background-color: #f15e0f;
  }
  .two {
    background-color: #a532f1;
  }
  .three {
    background-color: #2274a5;
  }

  .droptarget {
    border: 10px dashed white;
    transition: border-width 0.5s linear;
  }

  .hover {
    border-width: 20px;
  }

</style>
<div class="container">
  <div class="draggable one" draggable="true">
    drag me
  </div>
  <div class="draggable two" draggable="true">
    drag me
  </div>
  <div class="draggable three" draggable="true">
    drag me
  </div>
  <div class="droptarget">drop here</div>
  <div class="droptarget">drop here</div>
  <div class="droptarget">drop here</div>
</div>
document.querySelectorAll('.draggable').forEach(item => {
  item.addEventListener('dragstart', event => {
    event.dataTransfer.setData('text/plain', getComputedStyle(item).backgroundColor)
  })
})

document.querySelectorAll('.droptarget').forEach(item => {
  item.addEventListener('dragover', event => {
    event.preventDefault()
  })
  item.addEventListener('dragleave', event => {
    item.classList.remove('hover')
  })
  item.addEventListener('dragenter', event => {
    item.classList.add('hover')
  })

  item.addEventListener('drop', event => {
    item.style.backgroundColor = event.dataTransfer.getData('text/plain')
  })
})

利用 setData 方法设置对拖拽元素写入特定的信息,然后在放置元素读取信息来展示不同的效果。

结语

静下心来过一下其实这些东西也没那么复杂,看完之后对那些 dnd 轮子项目也差不多了解其中的架构吧。

参考资料:

喵~