可拖动目标
默认情况下图片、链接、文本(需要选中)是可以拖动的,其他元素也可以拖动,但是需要设置draggable属性,表示属性是否可以拖动,图片和链接的draggable属性自动设置成了true,其他元素默认为false。当需要元素可以拖动或设置图片不可拖动时可以设置dragable属性,例如:
//可拖动的div
<div draggable="true"></div>
//不可拖动的图片
<img src="" draggable="false"></img>
拖动事件
当一个可拖动元素进行拖放时,会按顺序触发下列事件:
- dragstart
- drag
- dragend
当鼠标移动到元素上,按住鼠标并开始移动的那一刻会触发dragstart事件;当拖住元素移动过程中会不断触发drag事件;当松开鼠标,元素被放置到可放置目标或不可放置目标上时会触发dragend事件。
放置事件
当一个元素被放置到放置目标上时放置目标会触发以下事件:
- dragenter
- dragover
- dragleave或drop
当拖动元素拖动到放置目标上时会触发dragenter。
dragenter触发后会立即触发dragover事件,并且元素在放置目标范围内被拖动期间会一直持续触发。
拖动元素离开放置目标会触发dragleave事件。
当元素被放置到目标元素范围内时会触发drop事件。
自定义放置目标
当把元素拖放到无效放置目标上时,会看到一个特殊光标(圆环中间一条斜杠)。所有元素都支持放置,但是默认是不可放置的,如果把元素拖放到不可放置目标上时是不会触发drop事件的。我们可以通过覆盖dragenter和dragover的默认行为让所有元素都转换为有效的放置目标:
const box=document.querySelector(".box")
box.ondragenter=(event)=>{
event.preventDefault()
}
box.ondragover=(event)=>{
event.preventDefault()
}
执行上面代码后,把元素拖动到这个div元素上时,可以看到光标变成可放置的样子,并且可以触发drop事件。
在Firefox浏览器中,放置事件的默认行为是导航到放在放置目标上的URL。这意味着拖动图片会导航的图片的URL,拖动文本会导航到无效URL。为阻止这个默认行为,我们在Firefox必须阻止drop的默认行为:
box.ondrop=(event)=>{
event.preventDefault()
}
dataTransfer对象
dataTransfer对象主要功能是进行拖拽过程中的数据传输,
属性
dropEffect
告诉浏览器允许那种放置行为,有下列值:
- ”none“:被拖动元素不能放到这里,光标效果:圆环中间一条斜杠
- "move":被拖动元素应该移动到放置目标,光标效果:虚线方框
- "copy":被拖动元素应该复制到放置目标,光标效果:虚线方框下一个加号
- "link":放置目标会导航到被拖动元素,光标效果:虚线方框下一个黑色箭头
dropEffect设置后只会有光标效果,不会自动移动、复制链接,具体移动、复制还是链接被拖动元素还需代码实现。红宝书上面写的”必须在ondragenter中设置dropEffect“,但是也可以在ondragover中设置dropEffect,并且光标会更合逻辑。例如,
- 如果在ondragenter中设置dropEffect,dropEffect好像并没有起作用,光标只会和允许的effectAllowed值一样,并且dropEffect为none时也能放置拖拽元素
- 如果在ondragover中设置dropEffect,dropEffect值如果和effectAllowed冲突,不会触发drop事件,光标为不可放置(圆环中间一条斜杠),并且dropEffect值为none时不会触发drop事件
需要注意的是:须同时设置effectAllowed,dropEffect才会生效,
effectAllowed
表示被拖动元素允许的dropEffect(其实就是允许的光标效果),有如下几个值:
- “uninitiated”:没有任何效果
- “none”:被拖动元素没有被允许的操作
- ”move“:只允许move的dropEffect
- ”copy“:只允许copy的dropEffect
- ”link“:只允许link的dropEffect
- ”copyMove“:允许copy和move的dropEffect
- ”copyLink“:允许copy和link的dropEffect
- ”linkMove“:允许link和move的dropEffect
- ”all“:允许所有dropEffect
要设置effectAllowed,必须在dragstart事件中设置。需要注意的是:如果effectAllowed的值为none时,不会触发drop
files
和fileList对象,如果拖拽的是一个文件,可以在files中获取文件信息
items
items是一个对象数组,每个对象有一个kind和type属性。当通过setData(format,data)传递的数据时,items属性会记录kind:数据的类型,type:format,结构:
[
{kind:string,type:format}
]
types
一个数组,记录传递数据的MIME类型
方法
setData(format,data)
format和data都是字符串类型。用于存储数据,只能在ondragstart中使用
getData(format)
format字符串类型。用于获取setData存储的数据
clearData(format)
format字符串类型。用于清除存储的数据,只能在ondragstart中使用,因为这是拖动操作的数据存储唯一能写入的时间
setDragImage(element,x,y)
element可以是任何元素,光标位置的图片上的x和y坐标。用来设置拖动发生时显示在光标下的图片,通常在ondragstart 事件中调用此方法。
拖动文件上传
-
创建一个div
<div id="drag"></div> -
获取div,阻止默认行为将div转换为可放置目标:
const box=document.querySelector("#drag") box.ondragenter=(event)=>{ event.preventDefault() } box.ondragover=(event)=>{ event.preventDefault() } -
在drop事件中获取文件
box.ondrop=(event)=>{ const file=event.dataTransfer.files[0]//获取拖动的文件 }
demo:
拖动元素
html结构:
<div class="flex">
<div class="drag">
<div draggable="true" id="div" class="div"></div>
<p draggable="true" id="p" class="p">这是一段文本</p>
</div>
<div class="drop"></div>
</div>
javascript:
const drag=document.querySelector('.drag')
const drop=document.querySelector('.drop')
drag.ondragstart=(e)=>{
e.dataTransfer.setData("id",e.target.id)
}
drop.ondragenter=(e)=>{
e.preventDefault()
}
drop.ondragover=(e)=>{
e.preventDefault()
}
drop.ondrop=(e)=>{
const id=e.dataTransfer.getData("id")
e.target.append(document.querySelector("#"+id))
e.preventDefault();
}
demo: