巨详细!帮你踩坑HTML5拖拽api(上)
去年换工作之后,到手第一个负责的模块就是类低代码平台,研究了一下市面上的拖拽库,没有特别符合需求的,所以就打算自己梭哈一个,就去研究了一下h5的拖拽api,在这个过程中也遇到了一些坑,因为文章太长,所以分为上下两篇,第一篇就先讲解一下拖拽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>
2.2 DragEvent
当触发拖拽事件时候,会得到一个Event
对象,这个Event
对象其中包含这一些常用的属性
- target: 为拖拽中的元素的指向
- clientX: 当前鼠标的x点坐标
- clientY: 当前鼠标的y点坐标
- dataTransfer: 当一次拖拽开始发生的时候,会产生一个
DataTransfer
对象,这个DataTransfer
对象于整个拖拽过程触发的事件共享。当这一次的拖拽行为结束之后,这个对象会被销毁
2.3 DataTransfer
存放的数据只能在
dragstart
中存放,存放之后,在drag
和dragend
中拿不到
这个对象用于保存在 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
的图片位于鼠标中心
我们可以单独设置拖拽显示的图片,比如下面的图标
const image = new Image()
image.src = './drag.jpg'
dragBox.addEventListener('dragstart', function (e) {
e.dataTransfer.setDragImage(image, 50, 50)
})
3 拖拽范围事件
当有个可以拖拽的元素之后,元素在拖拽的过程中,会经过一些元素,这里给他取一个形象一点的名称:过程元素
可以给这些过程元素绑定三个事件
- dragenter: 拖拽元素进入该
dom
时触发 - dragover: 拖拽元素在该
dom
范围内触发 - dragleave: 拖拽元素离开该
dom
时触发
<div class="process">过程元素</div>
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>
给目标元素绑定 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>
转载自:https://juejin.cn/post/7250041527069933626