突袭HTML5之Javascript API扩展4 - 拖拽

      拖拽(Drag/Drop)是个非常普遍的功能。你可以抓住一个对象,并且拖动到你想放置的区域。 很多javascript都类似实现了相关的功能,例如,jQueryUI的drag and drop组件。在HTML5中,拖拽(drag and drop)成为了标准操作,任何元素都支持。正因为这个功能太普遍了,所有的主流浏览器都支持这个操作。

启用拖拽 - draggable属性
      非常简单,只需要将一个元素的拖动属性修改为draggable,这个元素就支持拖动了,如下所示:

< img  draggable ="true"   /> 


拖动中数据的传递

      拖动的过程中,我们往往需要传递相应的逻辑数据来完成转换的过程,这里主要是使用dataTransfer对象进行数据传递,下面先看看它的成员:
方法成员:

setData(format, data):把被拖动的数据赋值给dataTransfer对象。

      format:一个String型参数,指定被拖动数据的类型。该参数取值可以是“Text”(文本类型)和“URL”(URL类型)。该参数是大小写无关的,所以传入"text"与"Text"是一样的。
      data:一个变体类型参数,指定被拖动的数据。该数据可以是文本,图片路径,URL等等。
      该函数有Boolean类型的返回值,true表示数据成功加到dataTransfer中,false代表不成功。如果需要,可以通过这个参数来决定是否应该继续执行某些逻辑。

getData(format):获取dataTransfer中存放的拖动数据。

      format意义与setData中的一样,取值可以是"Text"(文本类型)和"URL"(URL类型)。

clearData(format):移除指定类型的数据。

      这里的format除了上面可以指定的"Text"(文本类型)和"URL"(URL类型)外,还可以取下列值:file - 文件,html - html元素,image - 图片。
      这个方法可以用于去选择性的处理拖动的数据类型。
 

属性成员:

effectAllowed:设置或获取数据源元素中的数据可以执行的操作。

      属性类型为字符串,取值范围如下:
          "copy"-复制数据.
          "link"-链接数据.
          "move"-移动数据
          "copyLink"-复制或链接数据,由目标对象来确定。
          "copyMove"-复制或移动数据,由目标对象来确定。
          "linkMove"-链接或移动数据,由目标对象来确定。
          "all"-所有的操作都是支持的。
          "none"-禁止拖动。
          "uninitialized"-默认值,采用默认的行为。

      注意设置effectAllowed为none以后,拖动是禁止的,但是鼠标形状还是显示没有可拖动的对象的形状,如果想不显示这个鼠标形状,则需要将window的event事件的属性returnValue设置为false。

dropEffect:设置或获取拖动的目标上允许的操作以及相关的鼠标形状。

      属性类型为字符串,取值范围如下:
         "copy"-鼠标显示为复制时的形状;
         "link"-鼠标显示为连接的形状;
         "move"-鼠标显示为移动的形状。
         "none"(默认值)-鼠标显示为没有拖动的形状。

      effectAllowed指定了数据源支持的操作,所以通常在ondragstart事件中指定。dropEffect指定了拖动放置的目标支持的操作,所以与effectAllowed配合,通常在拖动的目标上的 ondragenter, ondragover和ondrop等事件中使用。

files:返回拖动的文件的列表FileList。
types:ondragstart中发送的数据(被拖动的数据)类型的列表。

      dataTransfer对象的存在,使得在拖动的数据源和目标元素之间传递逻辑数据变成了可能。通常我们使用setData方法在数据源元素的ondragstart事件中提供数据,然后再目标元素中,使用getData方法获取数据。

 

拖动中触发的事件
      下面是一次拖拽会发生的事件,基本上事件的触发顺序也就是下面的顺序:

dragstart:要被拖拽的元素开始拖拽时触发,这个事件对象是被拖拽元素。
drag:拖拽元素时触发,这个事件对象是被拖拽元素。
dragenter:拖拽元素进入目标元素时触发,这个事件对象是目标元素。
dragover:拖拽某元素在目标元素上移动时触发,这个事件对象是目标元素。
dragleave:拖拽某元素离开目标元素时触发,这个事件对象是目标元素。
drop:将被拖拽元素放在目标元素内时触发,这个事件对象是目标元素。
dragend:在drop之后触发,就是拖拽完毕时触发,这个事件对象是被拖拽元素。

      基本上事件的参数event都会传入相关的元素,可以很方便的进行一些修改。这里,我们并不需要处理每个事件,通常只需要挂接主要的几个事件即可。

拖动开始 - ondragstart事件
      从这个事件传入的参数含有的信息非常丰富,从中可以很方便的获取到被拖动的元素(event.Target);从中可以设置被拖动数据(event.dataTransfer.setData);所以你可以很方便实现拖动的背后逻辑(当然你绑定的时候也可以传递其他的参数)。
拖动过程中 - ondrag,ondragover,ondragenter和ondragleave事件
      ondrag事件的对象是被拖拽元素,通常这个事件处理的比较少。ondragenter事件是当拖动进入当前元素时发生,ondragleave事件是在当拖动离开当前元素时发生,ondragover事件是在拖动在当前元素中移动时发生。
      这里只需要注意一点,因为默认情况下,浏览器是禁止元素drop的,所以为了让元素可以drop,需要在这个函数中返回false或者调用event.preventDefault()方法。如下面的例子所示。
拖动结束 - ondrop,ondragend事件
      当可拖动的数据被drop的时候,drop事件触发。drop结束后,dragend事件被触发,这个事件使用的也相对少一点。

      看一个简单的例子:

<! DOCTYPE HTML >
< html >
< head >
< script  type ="text/javascript" >
  
function  allowDrop(ev){
    ev.preventDefault();
  }
  
function  drag(ev){
    ev.dataTransfer.setData(
" Text " ,ev.target.id);
  }
  
function  drop(ev){
    
var  data = ev.dataTransfer.getData( " Text " );
    ev.target.appendChild(document.getElementById(data));
    ev.preventDefault();
  }
</ script >
</ head >
< body >
   < div  id ="div1"  ondrop ="drop(event)"  ondragover ="allowDrop(event)" ></ div >
   < img  id ="drag1"  src ="img_logo.gif"  draggable ="true"  ondragstart ="drag(event)"  width ="336"  height ="69"   />
</ body >
</ html >

 

文件拖拽
      上面的例子已经使用了dataTransfer的各种方法和属性,下面再看网上的另外一个有趣的应用:拖拽一个图片到网页上,然后在网页上显示。这个应用用到了dataTransfer的files属性。

<! DOCTYPE HTML >
< html >
< head >
  < meta  charset ="utf-8" >
     < title >HTML5拖放文件 </ title >
     < style >
  #section
{ font-family :  "Georgia", "微软雅黑", "华文中宋" ; }
        .container
{ display : inline-block ; min-height : 200px ; min-width : 360px ; color : #f30 ; padding : 30px ; border : 3px solid #ddd ; -moz-border-radius : 10px ; -webkit-border-radius : 10px ; border-radius : 10px ; }
  .preview
{ max-width : 360px ; }
  #files-list
{ position : absolute ; top : 0 ; left : 500px ; }
  #list
{ width : 460px ; }
  #list .preview
{ max-width : 250px ; }
  #list p
{ color : #888 ; font-size : 12px ; }
  #list .green
{ color : #09c ; }
    
</ style >
</ head >
< body >
     < div  id ="section" >
         < p >把你的图片拖到下面的容器内: </ p >
         < div  id ="container"  class ="container" >
         </ div >
   < div  id  ="files-list" >
    < p >已经拖进过来的文件: </ p >
    < ul  id ="list" ></ ul >
   </ div >
     </ div >
  < script >
 
if  (window.FileReader) {
  
var  list  =  document.getElementById( ' list ' ),
   cnt 
=  document.getElementById( ' container ' );

  
//  判断是否图片
   function  isImage(type) {
   
switch  (type) {
   
case   ' image/jpeg ' :
   
case   ' image/png ' :
   
case   ' image/gif ' :
   
case   ' image/bmp ' :
   
case   ' image/jpg ' :
    
return   true ;
   
default :
    
return   false ;
   }
  }

  
//  处理拖放文件列表
   function  handleFileSelect(evt) {
   evt.stopPropagation();
   evt.preventDefault();

   
var  files  =  evt.dataTransfer.files;
   
for  ( var  i  =   0 , f; f  =  files[i]; i ++ ) {
    
var  t  =  f.type  ?  f.type :  ' n/a ' ,
     reader 
=   new  FileReader(),
     looks 
=   function  (f, img) {
      list.innerHTML 
+=   ' <li><strong> '   +  f.name  +   ' </strong> ( '   +  t  +
       
' ) -  '   +  f.size  +   '  bytes<p> '   +  img  +   ' </p></li> ' ;
      cnt.innerHTML 
=  img;
     },
     isImg 
=  isImage(t),
     img;

    
//  处理得到的图片
     if  (isImg) {
     reader.onload 
=  ( function  (theFile) {
      
return   function  (e) {
       img 
=   ' <img class="preview" src=" '   +  e.target.result  +   ' " title=" '   +  theFile.name  +   ' "/> ' ;
       looks(theFile, img);
      };
     })(f)
     reader.readAsDataURL(f);
    } 
else  {
     img 
=   ' "o((>ω< ))o",你传进来的不是图片!! ' ;
     looks(f, img);
    }
   }
  }
  
  
//  处理插入拖出效果
   function  handleDragEnter(evt){  this .setAttribute( ' style ' ' border-style:dashed; ' ); }
  
function  handleDragLeave(evt){  this .setAttribute( ' style ' '' ); }

  
//  处理文件拖入事件,防止浏览器默认事件带来的重定向
   function  handleDragOver(evt) {
   evt.stopPropagation();
   evt.preventDefault();
  }
  
  cnt.addEventListener(
' dragenter ' , handleDragEnter,  false );
  cnt.addEventListener(
' dragover ' , handleDragOver,  false );
  cnt.addEventListener(
' drop ' , handleFileSelect,  false );
  cnt.addEventListener(
' dragleave ' , handleDragLeave,  false );
  
 } 
else  {
  document.getElementById(
' section ' ).innerHTML  =   ' 你的浏览器不支持啊,同学 ' ;
 }
 
</ script >
</ body >
</ html >

      这个例子中使用了html5中的文件读取API:FileReader对象;该对象提供了下列异步方法用于读取文件:
1. FileReader.readAsBinaryString(fileBlob)
  以二进制的方式读取文件,result 属性会包含一个文件的二进制的格式
2. FileReader.readAsText(fileBlob, opt_encoding)
  以文本的方式读取文件, result 属性将会包含一个文件的文本格式,默认解码参数是 “utf-8”。
3. FileReader.readAsDataURL(file)
  以URL形式读取文件result 将会包含一个文件的 DataURL 格式(图片通常用这种方式)。

当使用上面的方法读取文件后,会触发下列事件:

onloadstart,onprogress,onabort,onerror,onload,onloadend

这些事件都很简单,需要的时候挂接就可以了。看下面的代码示例:

function startRead() {  
   //  obtain input element through DOM 
  
   var file = document.getElementById('file').files[0];
   if(file){
    getAsText(file);
  }
}

function getAsText(readFile) {
   var reader =  new FileReader();  
   //  Read file into memory as UTF-16      
  reader.readAsText(readFile, "UTF-16");  
   //  Handle progress, success, and errors
  reader.onprogress = updateProgress;
  reader.onload = loaded;
  reader.onerror = errorHandler;
}

function updateProgress(evt) {
   if (evt.lengthComputable) {
     //  evt.loaded and evt.total are ProgressEvent properties
     var loaded = (evt.loaded / evt.total);
     if (loaded < 1) {
       //  Increase the prog bar length
       //  style.width = (loaded * 200) + "px";
    }
  }
}

function loaded(evt) {  
   //  Obtain the read file data    
   var fileString = evt.target.result;
   //  Handle UTF-16 file dump
   if(utils.regexp.isChinese(fileString)) {
     // Chinese Characters + Name validation
  }
   else {
     //  run other charset test
  }
   //  xhr.send(fileString)     
}

function errorHandler(evt) {
   if(evt.target.error.name == "NotReadableErr") {
     //  The file could not be read
  }
}

      这里也简单说一下:普通的文件下载使用的就是window.open方法,例如:

window.open('http://aaa.bbbb.com/ccc.rar','_blank')

 

实用参考:
官方文档:http://www.w3schools.com/html5/
一个不错的教程网站:http://html5.phphubei.com/html5/features/DrapAndDrop/
MSDN帮助:http://msdn.microsoft.com/en-us/library/ms535861(v=vs.85).aspx
文件拖拽详述:http://www.html5rocks.com/zh/tutorials/file/dndfiles/
文件拖拽并上传:http://www.chinaz.com/design/2010/0909/131984.shtml
文件拖拽上传完整例子:http://www.cnblogs.com/liaofeng/archive/2011/05/18/2049928.html
文件下载的例子:http://hi.baidu.com/guo_biru/item/2d7201c012b6debd0c0a7b05
window.open攻略:http://www.cnblogs.com/liulf/archive/2010/03/01/1675511.html
window.open参数:http://www.koyoz.com/blog/?action=show&id=176 

你可能感兴趣的:(突袭HTML5之Javascript API扩展4 - 拖拽)