• 突袭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 

  • 相关阅读:
    C++ 类的本质 札记
    eclipse makefile
    boost 简介
    telecom 产品分析js
    javascript 得到页面参数
    ajax 接口统一模式
    备份
    jquery 元素插入详解
    使用WebClient制作一下简单的采集器
    数据库锁机制
  • 原文地址:https://www.cnblogs.com/dxy1982/p/2626515.html
Copyright © 2020-2023  润新知