HTML5新增的拖放API

HTML5新增了关于拖放的API,通过拖放API可以让HTML页面的任意元素都变成可拖动的,通过使用拖放机制可以开发出更友好的人机交互界面。拖放操作可以分成两个动作:在某个元素上按下鼠标并移动鼠标(没有松开鼠标),此时开始拖动;在拖动过程中,只要没有松开鼠标,将会不断地产生拖动事件——这个过程被称为拖;把被拖动的元素拖动到另外一个元素上并松开鼠标——这个动作被称为放。拖放操作由拖和放两个动作组成。

浏览器支持

Internet Explorer 9、Firefox、Opera 12、Chrome 以及 Safari 5 支持拖放。

1.启动拖动

在HTML5中,<img/>元素默认就是可拖动的;而<a/>元素只要设置了href属性,它默认也是可拖动的。

<!DOCTYPE html>
<html>
<head>
	<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<title> 可拖动 </title>
</head>
<body>
<a href="http://www.baidu.com">百度一下</a>
<img src="baidu.jpg" alt="百度一下"/>
</body>
</html>

对于普通元素而言,如果希望把它变成可拖动的,我们只要把该元素的draggable属性设为true即可。但仅仅设置该元素的draggable属性还不够,因为仅仅设置了draggable=true只表示该元素可拖动,但拖动时并未携带数据,因此用户看不到拖动效果。为了让拖动操作能携带数据,应该为被拖动元素的ondragstart事件指定监听器,在该监听器中让拖动操作可以携带数据。例如下面代码所示。

<!DOCTYPE html>
<html>
<head>
	<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<title> 可拖动的Div </title>
</head>
<body>
<div id="source" style="width:80px;height:80px;
	border:1px solid black;
	background-color: #bbb;"
	draggable="true">百度一下</div>
<script type="text/javascript">
	var source = document.getElementById("source");
	source.ondragstart = function(evt)
	{
		// 让拖动操作携带数据
		evt.dataTransfer.setData("text/plain" , "百度一下");
	}
</script>
</body>
</html>

2.接受放的操作

不管是拖动图片,还是拖动<div/>元素,拖动时都显示了一个禁止标志,这表明拖动图片、拖动<div/>时,被拖到目的地并不接受被拖动的元素——这是因为当被拖动元素被拖过document对象时,document对象默认阻止了拖动事件,而其他HTML组件也是位于document对象内的,因此它们也不能接受放。为了让document可以接受放,应该为document的ondragover事件指定监听器,在监听器中取消document对拖动事件的默认行为。

注意:当我们把<div/>元素拖到指定位置释放后,Firefox浏览器默认会打开一个新页面,页面的URL正是拖放操作携带的数据。但如果使用Chrome浏览器来浏览该页面,当我们把<div/>元素拖到指定位置释放后,Chrome浏览器并没有执行任何默认动作。

由此可见,不同浏览器对于拖放操作的默认动作并不相同,如果开发者希望取消拖放操作的默认动作,则可以为document的ondrop事件绑定监听器。也就是再增加如下代码。

<!DOCTYPE html>
<html>
<head>
	<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<title> 可拖动的Div </title>
</head>
<body>
<div id="source" style="width:80px;height:80px;
	border:1px solid black;
	background-color: #bbb;"
	draggable="true">百度一下</div>
<script type="text/javascript">
	var source = document.getElementById("source");
	source.ondragstart = function(evt)
	{
		// 让拖动操作携带数据
		evt.dataTransfer.setData("text/plain" , "www.baidu.com");
	}
	document.ondragover = function(evt)
	{
		evt.preventDefault();
		// 取消事件的默认行为
		return false;
	}
	document.ondrop = function(evt)
	{
		evt.preventDefault();
		// 取消事件的默认行为
		return false;
	}
</script>
</body>
</html>

在我们拖放HTML元素的过程中,可能触发如下表所示的事件。

事件事件源描述
ondragstart被拖动的HTML元素开始拖动时触发该事件
ondrag被拖动的HTML元素拖动过程中会不断的触发该事件
ondragend被拖动的HTML元素拖动结束时触发该事件
ondragenter拖动时鼠标经过的元素被拖动的元素进入本元素范围内时触发该事件
ondragover拖动时鼠标经过的元素被拖动的元素进入本元素范围内拖动时会不断的触发该事件
ondragleave拖动时鼠标经过的元素被拖动的元素离开本元素时触发该事件
ondrop拖动时鼠标经过的元素其他元素被放到本元素中时触发该事件

如果希望实现一个允许自由拖动的<div/>,这就比较简单了——只要监听document的ondrop方法,当用户把<div/>元素放到document中时,通过JavaScript代码把该元素移动到该位置即可。下面代码实现了一个可以自由拖动的<div/>元素。

<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<title> 可自由拖动的Div </title>
</head>
<body>
<div id="source" style="width:80px;height:80px;
	border:1px solid black;
	background-color: #bbb;"
	draggable="true">百度一下</div>
<script type="text/javascript">
	var source = document.getElementById("source");
	source.ondragstart = function(evt)
	{
		// 让拖动操作携带数据
		evt.dataTransfer.setData("text/plain" , "www.baidu.com");
	}
	document.ondragover = function(evt)
	{
		// 取消事件的默认行为
		return false;
	}
	document.ondrop = function(evt)
	{
		source.style.position = "absolute";
		source.style.left = evt.pageX + "px";
		source.style.top = evt.pageY + "px";
		// 取消事件的默认行为
		return false;
	}
</script>
</body>
</html>

上面代码把<div/>元素的left属性设为evt事件发生点的X坐标,top属性设为evt事件发生点的Y坐标,这样就可以把<div/>元素移动到指定位置。

3.DataTransfer对象

拖放触发的拖放事件有一个dataTransfer属性,该属性值是一个DataTransfer对象,该对象包含如下属性和方法。

属性和方法描述
dataTransfer.dropEffect设置或返回拖放目标上允许发生的拖放行为。如果此处设置的拖放行为不在effectAllowed属性设置的多种拖放行为之内,拖放操作将会失败。该属性值只允许为none、copy、link和move四个值之一。
dataTransfer.effectAllowed设置或返回被拖动元素允许发生的拖动行为。该属性值可设置为none、copy、copyLink、copyMove、link、linkMove、move、all和uninitialized。
dataTransfer.items该属性返回DataTransferItems对象,该对象代表了拖动数据。
dataTransfer.setDragImage(element, x, y)设置拖放操作的自定义图标。其中element设置自定义图表,x设置图标与鼠标在水平方向的距离;y设置图标与鼠标在垂直方向的距离。
dataTransfer.addElement(element)添加自定义图标。
dataTransfer.types该属性返回一个DOMStringList对象,该对象包括了存入dataTransfer中数据的所有类型。
dataTransfer.getData(format)获取DataTransfer对象中format格式的数据。
dataTransfer.setData(format, data)向DataTransfer对象中设置format格式的数据。其中format代表数据格式,data代表数据。
dataTransfer.clearData([format])清除DataTransfer对象中format格式的数据。如果省略format格式,则意味着清除DataTransfer对象中的全部数据。

通过DataTransfer对象,可以让拖放操作实现更丰富的功能——我们可以在拖放开始时(ondragstart事件)将拖放源的数据存入DataTransfer对象中,然后在拖放结束时从DataTransfer对象中读取数据,这样就可以完成更复杂的拖放操作了。下面代码实现了一个允许通过拖放来添加、删除收藏项的功能。

<!DOCTYPE html>
<html>
<head>
	<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<title> 通过拖放实现添加、删除 </title>
	<style type="text/css">
		div>div{
			display: inline-block;
			padding: 10px;
			background-color: #aaa;
			margin: 3px;
		}
	</style>
</head>
<body>
<div style="width:600px;border:1px solid black;">
<h2>可将喜欢的项目拖入收藏夹</h2>
<div draggable="true" ondragstart="dsHandler(event);">11111111111</div>
<div draggable="true" ondragstart="dsHandler(event);">22222222222</div>
<div draggable="true" ondragstart="dsHandler(event);">33333333333</div>
<div draggable="true" ondragstart="dsHandler(event);">44444444444</div>
</div>
<div id="dest"
	style="width:400px;height:260px; 
	border:1px solid black;float:left;">
	<h2 ondragleave="return false;">收藏夹</h2>
</div>
<img id="gb" draggable="false" src="garbagebin.png"
	alt="垃圾桶" style="float:left;"/>
<script type="text/javascript">
	var dest = document.getElementById("dest");
	// 开始拖动事件的事件监听器
	var dsHandler = function(evt)
	{
		// 将被拖动元素的innerHTML属性值设置成被拖动的数据
		evt.dataTransfer.setData("text/plain"
			, "<item>" + evt.target.innerHTML);
	}
	dest.ondrop = function(evt)
	{
		evt.preventDefault();
		var text = evt.dataTransfer.getData("text/plain");
		// 如果该text以<item>开头
		if (text.indexOf("<item>") == 0)
		{
			// 创建一个新的div元素
			var newEle = document.createElement("div");
			// 以当前时间为该元素生成一个唯一的ID
			newEle.id = new Date().getUTCMilliseconds();
			// 该元素内容为“拖”过来的数据
			newEle.innerHTML = text.substring(6);
			// 设置该元素允许拖动
			newEle.draggable="true";
			// 为该元素的开始拖动事件指定监听器
			newEle.ondragstart = function(evt)
			{
				// 将被拖动元素的id属性值设置成被拖动的数据
				evt.dataTransfer.setData("text/plain"
					, "<remove>" + newEle.id);
			}
			dest.appendChild(newEle);
		}
	}
	// 当把被拖动元素“放”到垃圾桶上时激发该方法。
	document.getElementById("gb").ondrop = function(evt)
	{
		var id = evt.dataTransfer.getData("text/plain");
		// 如果id以<remove>开头
		if (id.indexOf("<remove>") == 0)
		{
			// 根据“拖”过来的数据,获取被拖动的元素
			var target = document.getElementById(id.substring(8));
			// 删除被拖动的元素
			dest.removeChild(target);
		}
	}
	document.ondragover = function(evt)
	{
		// 取消事件的默认行为
		return false;
	}
	document.ondrop = function(evt)
	{
		// 取消事件的默认行为
		return false;
	}
</script>
</body>
</html>

4.拖放行为

通过设置DataTransfer对象的effectAllowed、dropEffect两个属性可以控制拖放行为。effectAllowed用于控制被拖动元素的拖动行为,因此通常建议在ondragstart事件监听器中设置DataTransfer对象的effectAllowed属性;而dropEffect则控制被“放”入的目标组件的行为,因此通常建议在ondragover事件监听器中设置DataTransfer对象的dropEffect属性。如果dropEffect设置的拖放行为不在effectAllowed属性设置的多个拖放行为之内,拖放操作将会失败。具体来说,需要注意如下4点:

  1. 如果effectAllowed设为none,则不允许拖动该元素。
  2. 如果dropEffect设置为none,则被拖动的元素不能“放”到本元素中。
  3. 如果effectAllowed设置为all或不设置,则dropEffect可设置为任何属性值(因为都在all范围之内),而且将会遵守dropEffect指定的拖放行为。
  4. 如果effectAllowed指定了特定的拖放行为,例如move、copy等,那么dropEffect指定的属性值必须是effectAlllowed指定的多个属性值的子集。

下面代码示范了修改effectAllowed属性的效果。

<!DOCTYPE html>
<html>
<head>
	<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<title> 拖放行为 </title>
</head>
<body>
<div id="source" draggable="true" style="width:80px;height:60px;
	border:1px solid black;">拖动我</div>
<script type="text/javascript">
	var source = document.getElementById("source");
	var dest = document.getElementById("text/plain");
	source.ondragstart = function(evt)
	{
		var dt = evt.dataTransfer;
		// 可设置move、copy等属性值看看效果
		dt.effectAllowed = 'link';	
		dt.setData("text/plain", "www.fkjava.org");
	}
	// 允许拖动
	document.ondragover = function(e){return false;};
	document.ondrop = function(e){return false;};
</script>
</body>
</html>

5.改变拖放图标

通过调用DataTransfer对象的setDragImage还可以改变拖放图标,例如,把上一个例子的JavaScript脚本改为如下形式。my.gif图片自己添加一个放到同级目录即可。

<!DOCTYPE html>
<html>
<head>
	<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<title> 拖放行为 </title>
</head>
<body>
<div id="source" draggable="true" style="width:80px;height:60px;
	border:1px solid black;">拖动我</div>
<script type="text/javascript">
	var source = document.getElementById("source");
	var dest = document.getElementById("text");
	var myIcon = document.createElement("img");
	myIcon.src = "my.gif";
	source.ondragstart = function(evt)
	{
		var dt = evt.dataTransfer;
		// 可设置move、copy等属性值看看效果
		dt.effectAllowed = 'link';
		dt.setDragImage(myIcon , 0 , 0);
		dt.setData("text/plain", "www.baidu.com");
	}
	// 允许拖动
	document.ondragover = function(e){return false;};
</script>
</body>
</html>

 

------------如果大家喜欢我的博客,可以点击左上角的关注哦。

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值