主要的应用场景:拖拽排序,拖拽上传文件,头像拖拽裁剪
拖拽的流程:
确定可拖拽的内容 -> 开始拖拽 -> 拖拽过程(可放置内容/不可放置内容) -> 结束拖拽
涉及的知识点:
- 确定可拖拽的内容:draggable属性标识哪些内容是可拖拽的
- 开始拖拽:触发一个dragstart事件,标识开始拖拽了
- 拖拽过程:在拖着的过程中不断的触发,drag,dragenter,dragleave,drapover事件
- 结束拖拽:容器会触发drop事件,拖拽内容触发一个dragend事件
确定可拖拽的内容
首先我们必须在那些可拖拽的内容上设置一个draggable属性,表示这个元素是可以拖拽的
开始拖拽
当鼠标移动时,这个元素会触发一个dragstart事件,表示拖拽开始了
拖拽过程
当拖拽过程中,拖拽的元素会不断的触发drag事件,而当离开容器后,容器会触发一个dragleave事件,当把拖拽元素拖动到另外一个容器时,这个容器会触发dragenter事件,当这个元素在新容器内部不断拖动的时候,这个容器会不断触发dragover事件,当松开鼠标后,这个元素会触发一个drop事件,同时拖拽元素自身会触发一个dragend事件
draggable
直接设置在元素上,有三个值,true(可拖拽),false(不可拖拽),auto(自动根据浏览器识别,默认,通常默认可以拖拽的元素有img,带图片的object,带href属性的<a>,选中的文本)
<ol>
<li draggable="true">苹果</li>
<li draggable="false">栗子</li>
<li draggable="auto">橙子</li> <!--默认是auto-->
</ol>
DragEvent
dataTrabsfer.dropEffect
这个代表了鼠标这个图标的变化过程,例如可拖拽的,链接的,禁止的,它的值有
none:表示不可拖拽的,这个拖拽是无效的
move:表示当松开鼠标的时候,要将拖拽的内容放置到新的容器中
copy:表示当松开鼠标的时候,要将拖拽的内容复制一份到新的容器中
link:表示作为一个链接地址,可以是打开,显示等等
dataTrabsfer.effectAllowed
定义这个被拖拽的内容的效果是什么样的,比如只能被copy,只能被move还是即可以是copy也可以是move
这个属性只能在dragstart这个事件中设置,在开始拖拽的时候要确定效果是,move还是copy还是什么,这个属性用于在dragenter和dragover事件中初始化dropEffect
允许的值为:none,copy,copyLink,copyMove,link,linkMove,move,all,uninitialized
dataTrabsfer.setDragImage(element,x,y)
就是在拖动的过程中,在鼠标旁边有一个快照,显示的是拖拽的内容,可以通过这个知道正在拖拽的内容是什么,默认浏览器会自动生成一个
- element:传入的快照图像
- x和y参数:快照的偏移量,x代表鼠标的点击位置距离图片左侧边框的距离,y代表鼠标的点击位置距离图片顶部的距离
这个事件也只可以在dragstart事件中设置
dataTrabsfer.setData(format,data)
format
- 会自动转成小写字符
- 每个item中的type
- 同一种format存一份数据
- 以下format值会自动进行转换,text->text/plain,url->text/uri-list
同样,这个事件也只能在dragstart事件中保存拖拽数据
dataTrabsfer.getData(format,data)
format
- 会自动转成小写字符
- 每个item中的type
- 同一种format存一份数据
- 以下format值会自动进行转换,text->text/plain,url->text/uri-list
同样,这个事件也只能在dragstart事件中保存拖拽数据
案例
将列表中的项拖拽到另一个列表中
<div>
<ol id="one" ondragstart="dragSatrtHandler(event)" ondragend="dragEndHandler(event)">
<li draggable="true" data-value='苹果'>苹果</li>
<li draggable="true" data-value='栗子'>栗子</li>
<li draggable="true" data-value="橙子">橙子</li> <!--默认是auto-->
</ol>
<ol id="two" ondragover="dragOverHandler(event)" ondrop="dropHandler(event)">
</ol>
</div>
<script>
function dragSatrtHandler(event) {
console.log(event.target);
if(event.target instanceof HTMLLIElement){
let value=event.target.dataset.value;
console.log(value);
console.log(event.dataTransfer.effectAllowed);
event.dataTransfer.effectAllowed = 'move';
console.log(event.dataTransfer.effectAllowed);
event.dataTransfer.setData('text/plain',value);
//event.dataTransfer.effectAllowed = 'move';
}
else{
event.preventDefault()
}
}
function dragEndHandler(event){
if(event.dataTransfer.dropEffect === 'move'){
event.target.parentNode.removeChild(event.target);
}
else{
console.log('类型为:'+event.dataTransfer.dropEffect);
}
}
function dragOverHandler(event) {
event.preventDefault();
}
function dropHandler(params) {
console.log('li');
let li= document.createElement('li');
li.textContent=params.dataTransfer.getData('text/plain');
params.target.appendChild(li);
}
但是这个兼容有问题,移动端基本不兼容,而PC端兼容也不是特别好,IE的兼容很差,因此需要考虑到兼容方案
兼容方案
简单的说,就是用MouseEvent上的mousedown,mousemove,mouseover,mouseout,mouseup来模拟drop的各种操作
大致的对应关系
如果元素只有mousedown,那么我们不认为它是一个拖拽行为,只有当既有mousedown和mousemove时,我们才认为这个是一个拖拽行为
案例需要思考写,稍后上传代码