了解:
以前的web应用程序中通过mousemove或者mouseup等原来的事件来实现模拟拖放(drop&drag)功能。但是在HTML5中已经将实现拖放功能事件来实现拖放功能事件与API标准化,可以简单的实现以前要花费大量代码才能实现的功能。
HTML5的拖放,不仅可以通过鼠标移动浏览器中显示的Web部件,还可以将桌面上的文件拖放到浏览器中。这就是显著的提高了web应用程序界面便利性的原因之一。灵活运用File API不仅可以访问桌面文件名等Meta信息,还可以访问文件的内容。使用被拖放到浏览器中的桌面文件数据,可以在浏览器上进行非常有用,有趣的处理。File API是缩小Web应用程序与桌面应用程序差别的技术。
实际上,HTML5的拖放事件并非新开发的规范。原来在Internet Explorer5中就已经出现此种功能,后来被HTML5吸收了。但是,HTML5中对其进行功能的强化,变得比原来强大得多。到目前为止,Internet Explorer中还没支持所有HTML5的拖放规范,只能说一定程度上可以使用。在Chrome5和Safari 5以后支持了几乎所有HTML5的拖放功能。现在对HTML5的拖放功能支持最好的是Firefox3.6以后版本。Firefox中也支持File API,遗憾的是到目前为止支持File API的只有Firefox与Internet Explorer 9。
(1)案例
HTML5的拖放功能是在原先Internet Explorer 5中实现的功能基础上重新制定的标准。但是新的HTML5的拖放功能与原Internet Explorer中实现方式有所差别,不具备完全的互换性。因此这里首先制作可在Firefox、Safari、Chrome中运行的实例,然后再制作可在Internet Explorer中运行的实例。
HTML代码部分:
<!--放置可拖动的图标,4个img元素,1个div元素-->
<!--注意:在div元素中设置为draggable="true"只有设置了此draggable属性,并将属性值设置为true后,div元素才能被拖动-->
<div id="srcarea">
<img src="../../images/timg_1.jpg" alt="logo1" class="item" id="logo1">
<img src="../../images/timg_2.jpg" alt="logo2" class="item" id="logo2">
<img src="../../images/timg_3.jpg" alt="logo3" class="item" id="logo3">
<img src="../../images/timg_4.jpg" alt="logo4" class="item" id="logo4">
<div class="item" draggable="true" id="logo5"></div>
</div>
<div id="droparea">
<!-- 拖动目的区域-->
</div>
注意:在div元素中设置为draggable="true"。只有设置了此draggable属性,并将属性值设置为true后,div元素才能被拖动。而img元素以及设置了href属性的a元素,都是默认可被拖动的,不需要再设置draggable属性。当前,支持draggable属性的浏览器只有Chrome 5(之后的版本)、Safari 5。在Firefox 3.6以后的版本中,不管有没有设置此属性,只要在dataTranfer对象的setData()方法中设置了消息,就可被拖动。尽管在较旧的Safari 4中不支持draggable属性,也可借助CSS的力量,让div元素变成可被拖动的。代码如下:
[draggable=true]{
-webkit-user-drag:element;
}
先在拖动对象div元素中设置draggable="true",然后在CSS中追加上述代码。这样就相当于将设置的draggable="true"变得有意义了。使用这种CSS代码,不仅针对div元素,还可以将其他元素变成可被拖动。
CSS代码部分:
<style type="text/css">
#srcarea,#droparea{
width:1204px;
height: 200px;
background-color: lightgray;
border: 2px inset gray;
box-shadow: -1px -1px 2px 2px gray;
box-sizing: border-box;
margin: 0px auto 15px auto;
}
.item{
width: 120px;
margin-left:100px;
height: auto;
display: inline-block;
}
div.item{
height: 100px!important;
background-color: aqua;
}
/* 兼容Safari 4*/
[draggable=true]{
-webkit-user-drag:element;
}
</style>
此时的效果图(未添加JS)(Firefox运行环境)
添加JS(不考虑IE浏览器前提):
// JavaScript Document
//不考虑IE浏览器的前提
(function(){
/*——--------------------
*页面导入时的处理
*-----------------------*/
window.addEventListener("load",function(){
//取得拖动元素
var els=document.querySelectorAll("#srcarea [class=item]");
for(var i=0;i<els.length;i++){
//给拖动元素追加dragstart事件的处理代码
els[i].addEventListener('dragstart',function(evt){
var elm=evt.target;
evt.dataTransfer.setData("Text",elm.id);
evt.stopPropagation();
},false);
}
//给容纳领域追加各种事件处理
var droparea=document.getElementById("droparea");
droparea.addEventListener("dragenter",function(evt){
evt.preventDefault();
},false);
droparea.addEventListener("dragover",function(evt){
evt.preventDefault();
},false);
droparea.addEventListener("drop",function(evt){
var elm=evt.target;
var id=evt.dataTransfer.getData("Text");
var target=document.getElementById(id);
if(target){
droparea.appendChild(target);
}
evt.preventDefault();
},false);
},false);
})();
效果图(Firefox(左)、IE(右)):
可以清晰的看出:在IE中不可以拖放图片和div元素。
在上述代码中相关的事件:
事件名称 | 事件发生时机 |
dragstart | 拖动开始 |
drag | 拖动中(连续发生) |
dragend | 拖动结束时 |
事件名称 | 事件发生时机 |
dragenter | 拖动元素进入时 |
dragleave | 拖动元素拖出时 |
dragover | 拖动中(在进入过程中连续发生) |
drop | 拖动元素被放下时 |
在上述代码中,setData()方法的第1个参数中设置代表数据格式的字符串,如“Text”代码文本类型数据,这样第2个参数中必需设置文本数据。还可以设置“URL”等。标准中规定不管是大写还是小写,一律变换成小写字母。但是到目前为止不是所有的浏览器都遵循了这一标准。为了与IE相统一,设置为“Text”、“URL”比较适合。在dropstart事件使用stopPropagation()方法,为了不让事件传到父元素中,即父元素不会响应对应事件。如果父元素也是被悲拖动的元素,有可能发生意想不到的错误,因此填写stopPropagation()方法十分必要。在dragenter、dragover、drop三种事件的处理。所有的处理中都追加了preventDefault()方法,以抑制浏览器的默认动作。
JS代码兼容IE
// JavaScript Document
//兼容IE
//在IE的事件绑定与其他浏览器有所不同,有自己的方式。
(function(){
//页面导入时处理
add_event_listener(window,"load",function(){
//取得拖动元素
var els=get_draggable_items();
for(var i=0;i<els.length;i++){
//给拖动元素追加dragstart事件的处理代码
add_event_listener(els[i],'dragstart',function(evt){
var elm=event_target(evt);
evt.dataTransfer.setData("Text",elm.id);
stop_propagation(evt);
});
}
//给接收方区域追加各种事件处理
var droparea=document.getElementById("droparea");
add_event_listener(droparea,'dragenter',prevent_default);
add_event_listener(droparea,'dragover',prevent_default);
add_event_listener(droparea,"drop",function(evt){
var e=event_target(evt);
var id=evt.dataTransfer.getData('Text');
var target=document.getElementById(id);
if(target){
droparea.appendChild(target);
}
prevent_default(evt);
});
});
//取得拖动元素
function get_draggable_items(){
var els=null;
if(document.querySelectorAll){
els=document.querySelectorAll("#srcarea [class=item]");
}else{
var srcarea=document.getElementById("srcarea");
els=[];
for(var i=0;i<srcarea.childNodes.length;i++){
var el=srcarea.childNodes.item[i];
if(el.className==='item'){
els.push(el);
}
}
}
return els;
}
//设置事件侦听
function add_event_listener(elm,type,func){
if(!elm){return false;}
if(elm.addEventListener){
//兼容非IE
elm.addEventListener(type,func,false);
}else if(elm.attachEvent){
//兼容IE
elm.attachEvent('on'+type,func);
}else{
return false;
}
return true;
}
//抑制默认动作
function prevent_default(evt){
if(evt&&evt.preventDefault){
evt.preventDefault();
}else if(window.event){
//兼容IE
window.event.returnValue=false;
}
}
//停止事件上传
function stop_propagation(evt){
if(evt&&evt.stopPropagation){
evt.stopPropagation();
}else if(window.event){
//兼容IE
window.event.cancelBubble=true;
}
}
//取得事件发生元素
function event_target(evt){
if(evt && evt.target){
if(evt.target.nodeType===3){
return evt.target.parentNode;
}else{
return evt.target;
}
}else if(window.event&&window.event.srcElement){
return window.event.srcElement;
}else{
return null;
}
}
})();