drag api是h5中的新功能,用来拖拽页面元素挺有用的,先小结一下
首先,基本概念
声明,概念部分我是借鉴这篇文章 https://www.cnblogs.com/wuya16/p/DragApi.html
想让一个元素能拖动,需要在html中添加属性 draggable="true"。唯一特殊的应该是img标签,不加这个属性也可以拖动
<div id="blue" class="item" draggable="true"></div>
元素在拖放过程中触发的事件
先列下拖拽过程中可能触发的事件,如下:
- dragstart:事件主体是被拖放元素,在开始拖放被拖放元素时触发,。
- darg:事件主体是被拖放元素,在正在拖放被拖放元素时触发。
- dragenter:事件主体是目标元素,在被拖放元素进入某元素时触发。
- dragover:事件主体是目标元素,在被拖放在某元素内移动时触发。
- dragleave:事件主体是目标元素,在被拖放元素移出目标元素是触发。
- drop:事件主体是目标元素,在目标元素完全接受被拖放元素时触发。
- dragend:事件主体是被拖放元素,在整个拖放操作结束时触发。
其中事件主体是拖放元素的是,dragstart(开始拖动) 、darg(正在拖放) 、dragend(拖放结束),其他4个事件主体都是目标元素,进入、移动、离开、完全进入四个状态。
dataTransfer对象
只有简单的拖放而没有数据变化是没有什么用的。为了在拖放操作时实现数据交换HTML5定义了dataTransfer对象来传递拖拽的数据。
因为它是事件对象的属性,所以只能在拖放事件的事件处理程序中访问dataTransfer对象。在事件处理程序中,可以使用这个对象的属性和方法来 完善拖放功能。
getData()和setData()
dataTransfer对象有 getData()和setData()两个主要方法,操作dataTransfer中携带的数据。不难想象,getData()可以取得由setData()保存的值。setData()方法的第一个参数,也是getDAta()方法唯一的一个参数,表示保存的数据类型。
IE只定义了“text”和“URL”两种有效的数据类型,而HTML5则对此加以扩展,允许指定各种MIME类型。考虑到向后兼容,HTML5也支持“text”和“URL”,但这两种类型会被映射为“text/plain”和“text/uri-list”。如下所示:
- text/html:文本文字格式
- text/plain:HTML代码格式
- text/xml:XML字符格式
- text/url-list:URL格式列表
实际上,dataTransfer对象可以为每种MIME类型都保存一个值。换句话说,同时在这个对象中保存了一段文本和一个URL不会有任何问题。不过,保存在dataTransfer对象中的数据只能在drop事件处理程序中读取。如果在ondrop处理程序中没有读到数据,那就是dataTransfer对象已经被销毁,数据也丢失了。
在拖动文本框中的文本时,浏览器会调用setData()方法,将拖动的文本以“text”格式保存在dataTransfer对象中。类似地,在拖放链接或图像时,会调用setData()方法并保存URL。然后,在这些元素被拖放到放置目标时,就可以通过getData()读到这些数据。当然,作为开发人员,你也可以在dragstart事件处理程序中调用setData(),手工保存自己要传输的数据,以便将来使用。
将数据保存为文本和保存为URL是有区别的。如果将数据保存为文本格式,那么数据不会得到任何特殊处理。而如果将数据保存为URL,浏览器会将其当成网页中的链接。换句话说,如果你把它放置到另一个浏览器窗口中,浏览器就会打开该URL。
Firefox在其第5个版本之前不能正确地将“URL”和“text”映射为“text/uri-list”和“text/plain”。但是却能把“Text”映射为“text/plain”。为了更好地在跨浏览器的情况下从dataTransfer对象取得数据,最好在取得URL数据时检测两个值,而在取得文本数据时使用“text”。
var dataTransfer =event.dataTransfer;//读取URLvar url = dataTransfer.getData("url")|| dataTransfer.getData("text/uri-list");//读取文本var text = dataTransfer.getData("Text");
注意:一定要把短数据类型放在前面,因为IE 10及之前的版本仍然不支持扩展的MIME类型名,而它们在遇到无法识别的数据类型时,会抛出错误。
使用 setDragImage 方法设置拖放图标
在HTML5中,一个元素在被拖放时,还可以自定义拖放元素的鼠标图标。调用格式如下:
setDragImage(Element img,long x,long y);
setDragImage调用格式
img表示拖放时的 <> 元素的图标,x 表示图标距离鼠标指针的x轴方向的偏移值,y表示图标距离鼠标指针y轴方向的偏移值。
使用 effectAllowed 和 dropEffect 属性设置拖放效果
dataTransfer对象的两个属性:dropEffect和effectAllowed,能通过它来确定被拖动的元素以及作为放置目标的元素能够接受什么操作。结合effectAllowed 和 dropEffect 这两个属性,可以自定义拖放过程中的效果。两个属性虽然都是为了实现同一功能,但绑定的元素不同:effectAllowed属性作用于被拖放元素;而 dropEffect 属性作用于目标元素,
其中,通过dropEffect属性可以知道被拖动的元素能够执行哪种放置行为。这个属性有下列4个可能的值。
- none:不能把拖动的元素放在这里。这是除文本框之外所有元素的默认值。
- move:应该把拖动的元素移动到放置目标
- copy:应该把拖动的元素复制到放置目标
- link:表示放置目标会打开拖动的元素(但拖动的元素必须是一个链接,有URL)。
在把元素拖动到放置目标上时,以上每一个值都会导致光标显示为不同的符号。然而,要怎样实现光标所指示的动作完全取决于你。换句话说,如果你不介入,没有什么会自动地移动、复制,也不会打开链接。总之,浏览器只能帮你改变光标的样式,而其它的都要靠你自己来实现。要使用dropEfect属性,必须在ondraggenter事件处理程序中针对放置目标来设置它。
dropEffect属性只有搭配effectAllowed属性才有用。effectAllowed属性表示允许拖放元素的哪种dropEffect,effectAllowed属性可能的值如下。
- uninitialized:没有该被拖动元素放置行为。
- none:被拖动的元素不能有任何行为。
- copy:只允许值为“copy”的dropEffect。
- link:只允许值为“link”的dropEffect。
- move:只允许值为“move”的dropEffect。
- copyLink:允许值为“copy”和“link”的dropEffect。
- copyMove:允许值为“copy”和”link”的dropEffect。
- linkMove:允许职位“link”和”move”的dropEffect。
- all:允许任意dropEffect。
必须在ondraggstart事件处理程序中设置effectAllowed属性。
假设你想允许用户把文本框中的文本拖放到一个<div>元素中。首先,必须将dropEffect和effectAllowed设置为”move”。但是,由于<div>元素的放置事件的默认行为是什么也不做,所以文本不可能自动移动。重写这个默认行为,就能从文本框中移走文本。然后你就可以自己编写代码将文本插入到<div>中,这样整个拖放操作就完成了。如果将dropEffect和effectAllowed的值设置为”copy”,那就不会自动移走文本框中的文本。
其它属性
- addElement:事件主体是被拖放元素,为拖动操作添加一个元素。添加这个元素只影响数据(即增加作为拖动源而影响回调的对象),不会影响拖动操作时页面元素的外观。在写作文本时,只有Firefox 3.5+实现了这个方法。
- clearData:事件主体是目标元素,清除以特定格式保存的数据。实现这个方法的浏览器有IE、Firefox 3.5、Chrome和Safari 4+。
- types:当前保存的数据类型。这是一个类似数组的集合,以“text”这样的字符串形式保存着数据类型。实现这个属性的浏览器有IE10+、Firefox 3.5+和Chrome。
支持draggable属性的浏览器有IE10+、Firefox 4+、Safari 5+和Chrome。Opera 11.5以及之前的版本都不支持HTML5的拖放功能。另外,为了让Firefox 支持可拖动属性,还必须添加一个ondragstart事件处理程序,并在dataTransfer对象中保存了一些信息。
下面展示一个实例,功能就是两个框中的元素可以来回拖拽移动,拖动时显示自定义图片,并通过dataTransfer传递被拖拽元素的属性
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
#container{
width:800px;height:800px;
display: flex;justify-content: space-between;
align-items: flex-start;
}
#container1{
width:300px;height:500px;
border:2px dashed #ddd;
}
#container2{
width:300px;height:500px;
border:2px dashed #ddd;
}
.item{
width:100px;height:100px;
}
#red{
background: red;
}
#yellow{
background: yellow;
}
#blue{
background: blue;
}
</style>
</head>
<body>
<div id="container">
<div id="container1">
<div id="red" class="item" draggable="true"></div>
<div id="blue" class="item" draggable="true"></div>
</div>
<div id="container2">
<div id="yellow" class="item" draggable="true"></div>
<!--<img src="img/1.png" id="img" class="item" />
<a href="www.baidu.com" class="item" draggable="true" id="a">百度链接</a>
<input type="text" value="啦啦啦啦啦" draggable="true" id="text" class="item"/>-->
</div>
</div>
<script type="text/javascript">
//阻止默认,否则拖动时会显示禁止拖动的图标,也可以写在拖拽的目标元素上
document.ondragover=function(e){
e.preventDefault();
}
window.onload=function(){
var c1=document.getElementById("container1");
var c2=document.getElementById("container2");
var red=document.getElementById("red");
var yellow=document.getElementById("yellow");
var yellow=document.getElementById("yellow");
//定义一个图片,用作拖动时显示的图片
var img=document.createElement("img");
img.src="img/1.png";
c1.addEventListener("dragover",function(e){
//e.preventDefault(); //document上已经阻止了,这里就省了
})
c1.addEventListener("drop",function(e){
var dt = e.dataTransfer;
//获取被拖拽元素的id,是有dataTransfer传过来的
var id=dt.getData("text/html")
var item=document.getElementById(id);
e.target.appendChild(item); //将元素直接移动过来,原位置元素自动被remove
})
c2.addEventListener("dragover",function(e){
//e.preventDefault();
})
c2.addEventListener("drop",function(e){
var dt = e.dataTransfer;
var id=dt.getData("text/html")
var item=document.getElementById(id);
e.target.appendChild(item);
})
var item=document.getElementsByClassName("item");
//将可拖拽的元素循环绑定事件,一般绑定在dragstart上即可
for(let i=0;i<item.length;i++){
item[i].addEventListener("dragstart",function(e){
var dt = e.dataTransfer;
dt.effectAllowed="copy";
dt.setDragImage(img,25,25);
dt.setData("text/html",e.target.getAttribute("id"));
})
}
}
</script>
</body>
</html>