likes
comments
collection
share

巨详细!帮你踩坑HTML5拖拽api(上)

作者站长头像
站长
· 阅读数 18

去年换工作之后,到手第一个负责的模块就是类低代码平台,研究了一下市面上的拖拽库,没有特别符合需求的,所以就打算自己梭哈一个,就去研究了一下h5的拖拽api,在这个过程中也遇到了一些坑,因为文章太长,所以分为上下两篇,第一篇就先讲解一下拖拽api的时候,第二篇讲解下我遇到的哪些坑,解决方案是什么

下面是我开发出来的一小部分成果

巨详细!帮你踩坑HTML5拖拽api(上)

巨详细!帮你踩坑HTML5拖拽api(上)

废话不多说,开始进入学习时间!

1 添加拖拽特性

dom元素想要拖拽,只需要给dom绑定一个draggrable属性,就可以让这个dom添加上拖拽特性

<style>
  #box {
    width: 100px;
    height: 100px;
    background-color: red;
  }
</style>

<div id="box" draggable="true"></div>

2 拖拽事件

2.1 入门使用

h5对于可拖拽的元素,提供了下面三个事件用于拖拽监听

  • dragstart: 拖拽开始
  • drag: 拖拽中
  • dragend: 拖拽结束
<div id="box" draggable="true"></div>

<script>
  
  box.addEventListener('dragstart', function(e){
    console.log('拖拽开始')
  })

  box.addEventListener('drag', function(e){
    console.log('拖拽中')
  })
  
  box.addEventListener('dragend', function(e){
    console.log('拖拽结束')
  })
  
</script>

巨详细!帮你踩坑HTML5拖拽api(上)

2.2 DragEvent

当触发拖拽事件时候,会得到一个Event对象,这个Event对象其中包含这一些常用的属性

  • target: 为拖拽中的元素的指向
  • clientX: 当前鼠标的x点坐标
  • clientY: 当前鼠标的y点坐标
  • dataTransfer: 当一次拖拽开始发生的时候,会产生一个DataTransfer对象,这个DataTransfer对象于整个拖拽过程触发的事件共享。当这一次的拖拽行为结束之后,这个对象会被销毁

2.3 DataTransfer

存放的数据只能在dragstart中存放,存放之后,在dragdragend中拿不到

这个对象用于保存在 DragEvent 下的 dataTransfer中,可以用来存放拖拽过程中产生的一些数据

2.3.1 存放数据

存放数据有三个api

  • setData: 设置data
  • getData: 获取之前设置的data
  • clearData: 清除所有data

需要注意的是,存放数据传入的值,都会调用 toString 方法,转化为字符串

// 存
e.dataTransfer.setData('a', 1)
e.dataTransfer.setData('b', '2')
e.dataTransfer.setData('c', { a: '1', b: '2' })

// 取
e.dataTransfer.getData('a')     //  '1'
e.dataTransfer.getData('b')     //  '2'
e.dataTransfer.getData('c')     //  [ Object object ]

2.3.2 types

当存放了三个数据之后

e.dataTransfer.setData('a', 1)
e.dataTransfer.setData('b', '2')
e.dataTransfer.setData('c', { a: '1', b: '2' })

访问types能返回存放的key

e.dataTransfer.types   //  [ 'a', 'b', 'c' ]

2.4 设置拖拽图片

在拖拽发生的时候,会产生一个降低一点透明度的源dom的图片位于鼠标中心

巨详细!帮你踩坑HTML5拖拽api(上)

我们可以单独设置拖拽显示的图片,比如下面的图标

巨详细!帮你踩坑HTML5拖拽api(上)

const image = new Image()
image.src = './drag.jpg'

dragBox.addEventListener('dragstart', function (e) {
  e.dataTransfer.setDragImage(image, 50, 50)
})

巨详细!帮你踩坑HTML5拖拽api(上)

3 拖拽范围事件

当有个可以拖拽的元素之后,元素在拖拽的过程中,会经过一些元素,这里给他取一个形象一点的名称:过程元素

巨详细!帮你踩坑HTML5拖拽api(上)

可以给这些过程元素绑定三个事件

  • dragenter: 拖拽元素进入该dom时触发
  • dragover: 拖拽元素在该dom范围内触发
  • dragleave: 拖拽元素离开该dom时触发
<div class="process">过程元素</div>

巨详细!帮你踩坑HTML5拖拽api(上)

const process = document.querySelector('.process')
process.addEventListener('dragenter', function(e){  console.log('拖拽元素进入')})
process.addEventListener('dragover', function(e){  console.log('拖拽元素移动')})
process.addEventListener('dragleave', function(e){  console.log('拖拽元素离开')}) 

需要注意的是,这三个事件中,并不能拿到dragStart中设置的DataTransfer对象数据

4 放置事件

4.1 入门使用

当有可以拖拽的元素之后,总是需要有一个用于放置的地方,这个地方取一个形象的名称叫做目标元素。可以给目标元素绑定一个事件

  • drop: 拖拽元素松开的位置在目标元素中,会触发这个函数【在这个函数中可以拿到在dragStart中存储的DataTransfer

准备一个例子

<style>
  .target{  
    display: inline-block;  
    width: 200px;   
    height: 200px;  
    border: 1px dashed #000
  }
</style>

<div class="target">目标元素</div>

巨详细!帮你踩坑HTML5拖拽api(上)

给目标元素绑定 drop 事件

const target = document.querySelector('.target')
target.addEventListener('drop', function (e) {  
  console.log('松开')
})

尝试拖拽之后,会发现,这个函数根本没有被触发,这是因为还需要给目标元素绑定一个事件

dragover为拖拽元素进入到目标元素的时候,触发的函数。然后在这个函数中,执行阻止默认行为,表示允许拖拽元素放置在此元素中

这样,对应的drop就会触发

target.addEventListener('dragover', function (e) {  
  e.preventDefault()
})

4.2 drop:DataTransfer

只有在drop中能拿到dragStart存放的DataTransfer,这个参数中,还有一个files字段,借助这个字段,能实现文件拖拽上传的功能

例子如下

<div class="target">目标元素</div>
<script>  
  const target = document.querySelector('.target')
  target.ondragover = function (e) {    
    // 允许接受dom的放置    
    e.preventDefault() 
  }  
  target.ondrop = function (e) {    
    // 阻止默认行为,避免文件拖到浏览器会自动打开该文件    
    e.preventDefault()    
    // 文件会存放在e.dataTransfer.files中    
    console.log(e.dataTransfer.files[0])
  }
</script>