原生拖拽–根据数据判断是否可以被放置

dragstart可以写入数据,drop可以读取数据。其他的拖拽事件不可获取数据

但是往往人们需要动态得知是否可以被拖动放置,因此需要在dragover中获取到数据。

实现思路

将数据存放在window或者vuex中,将数据的id绑定在事件参数中,通过id获取原始数据,进而判断是否可以被放置

解决方案

  1. 在window中挂载数据对象,如dragData,在dragstart的时候,添加’text/${dataId}'数据项,这里的dataId即是数据的id,它应该在dragData中存在。
  2. 当dragover时,虽然e.dataTransfer.getData()方法获取不到数据,但是e.dataTransfer.types是可以拿到先前在dragstart中设置的’text/${dataId}'这个数据项的名字的,从这里可以解析出dataId
  3. 用dataId在dragData中查找即可获取被拖动的完整数据
  4. 当判定可以放置的时候,对dragover的参数 e,执行e.preventDefault()即可禁止浏览器默认对dragover的处理,使拖拽可以被放置。

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
ondragstart(e) {
e.dataTransfer.effectAllowed = 'copy'
e.dataTransfer.setData('text/plain', JSON.stringify(data))
e.dataTransfer.setData('text/' + dataId, dataId)
if (!window.dragData) {
window.dragData = {}
}
window.dragData[dataId] = data
}

ondragover(e) {
if (e.dataTransfer.types[1]) {
const dataId = e.dataTransfer.types[1].slice(5)
if (window.dragData) {
const data = window.dragData[dataId]
if (canDrop(data)) {
e.preventDefault()
}
}
} else {
e.preventDefault()
}
}

ondrop(e) {
try {
const data = JSON.parse(e.dataTransfer.getData('text/plain'))
console.log(data)
} catch (err) {
console.error(err)
}
}