【js学习笔记-096】----拖放事件

来源:互联网 发布:活性炭多久晒一次 知乎 编辑:程序博客网 时间:2024/05/16 14:30

【js学习笔记----拖放事件】

前面的篇幅中我们已经介绍过响应鼠标拖动。使用像那样的技术允许在网页上拖起“放置”元素,但真正的“拖放”是另一回事。拖放是在“拖放源”和“拖放目标”之间传输数据的用户界面,它可以存在相同的应用之间,也可以是不同应用之间。拖放是复杂的人机交互,用于实现拖放的API总是很复杂:

  •   它必须和底层的OS结合,使它们能够在不相关的应用间工作。
  •   它们必须适用于“移动”、“复制”和“链接”数据传输操作,允许拖放和拖放目标通过设置限制限制允许的操作,然后让用户选择(通常使用键盘辅助键)许可设置
  •   它们必须为拖放源提供一种方式指定待拖动的图标和图像
  •   它们必须为拖放源和拖放目标的DnD交互过程提供基于事件的通知

Microsoft IE早期版本就引入了DnD API。它并不是精心设计且精良的归档API,但其他浏览器都尝试复制它,且html5标准化了类似IE DnD API的东西,并增加了使API更易于使用的新特性。

draggable属性:任何html文档元素具有draggable属性的文档元素都是拖放源。当用户开始用鼠标在拖放源上拖动时,浏览器并没有选择元素内容,相对,它在这个元素上触发dragstart事件。这个事件的处理程序就调用dataTransfer.setData()指定当前可用的的拖放源数据(和数据类型)。(当新的html5 api实现时,可以用dataTransfer.items.add()代替。)这个事件的处理程序也可以设置dataTransfer.effectAllowed来指定支持“移动”、“复制”和“链接“传输操作中的几种,同时它可以调用dataTransfer.setDragImage()或dataTransfer.addElement()(在那些支持这些方法的浏览器中)指定图片或文档元素用做拖动时的视觉表现。在拖动过程中,浏览器在拖放源上触发拖动事件。如果想更新拖动图片或修改提供的数据,可以监听这些事件,但一般不需要注册”拖动“事件处理程序。

当放置数据发生时会触发dragstart 事件。如果拖放源支持” 移动“操作,它就会检查dataTransfer.dropEffect去看看是否实际执行了移动操作。如果执行了,数据就被传输到其他地方,你应该人拖放源中删除它。

例:一个自定义拖放源

<script src=”whenReady.js></script>

<script>

whenReady(function(){

    var clock =document.getElementById(“clock”); //时钟元素

    var icon =new Image(); //用于拖动的图片

      icon.src =“clock-icon.png”; //图片url

      //每分种显示一次时间

      functiondisplayTime(){

           varnow = new Date(); //获取当前时间

           var hrs = now.getHours(),mins =now.getMinutes();

         if(mins<10)mins=”0”+mins;

          clock.innerHTML = hrs+”:”+mins; //显示当前时间

          setTimeout(displayTime,60000); //一分钟后将再次运行

   

}

displayTime();

//使时钟能够拖动

//我们也能通过html属性实现这个目的:<span draggable=”true”>…

clock.draggable = true;

clock.ondragstart = function(event){

    var event = event || window.event; //用于兼容IE

    var dt = event.dataTransfer;

    //告诉浏览器正在拖动的是什么

    //把Date()构造函数用做一个返回时间戳字符器函数

      Dt.setData(“Text”,Date()+”\n”);

     //在支持的浏览器中,告诉它拖动图标来表现时间戳

    //没有这行代码,浏览器也可以使用时钟文本图像作为拖动的值

     If(dt.setDragImage)dt.setDragImage(icon,0,0);

};

 

});

 

</script>

<style>

#clock{

    font:bold24pt sans;background:#ddf;padding:10px;border:solid black 2px;

    border-radius:10px;

}

</style>

<h1>从时钟中播出时间戳</h1>

<span id=”clock”></span><!—时间显示在这里-->

<textareacols=60 rows=20></textarea> <!—把时间戳放置在这里-->

 

拖放目标比拖放源更棘手。任何文档元素都可以是拖放目标。这不需要拖放源一样设置html属性。只需要简单地定义合适的事件监听程序。(在html5DnD API,将可以在拖放目标上定义dropzone属性来取代定义后面介绍的一部分事件处理程序)

dragenter事件

dragover事件

dragleave事件

drop事件 事件处理程序使用dataTransfer.getData()获取传输的数据并做一些适当的处理。另外,如果用记在拖放目标放置一个或多个文件,dataTransfer.files属性是一个类数组的File对象。使用新的html 5 API ,drop事件处理程序将能遍历dataTransfer.items[]的元素去检查文件和非文件数据。

例:演示如何使<ul>元素成为拖放目标,同时如何使它们中的<li>元素成为拖放源。它查找class属性包含 “dnd”的<ul>元素,在它找到的此类列表上注册DnD事件处理程序。这些事件处理程序使列表本身成为拖放目标,在这个列表上放置的任何文本会变成新的列表项并插入到列表尾部。这些事件处理程序也监听列表项的拖动,使得每个列表项的文本可用于传输。拖放源事件处理程序允许“复制”和“移动”操作,并在移动操作下放置对象时会删除原有列表项。

例:作为拖放目标和拖放源的列表

/*

  DnD API相当复杂,且浏览也不完全兼容

 这个例子基本正确,但每个浏览器会有一点不同,每个似乎都有自身独有的bug

这些代码不会尝试浏览器特有的解决方案

*/

 

 

whenReady(function(){

      //查找所有的<ul class=’dnd’>元素,并对其调用dnd()函数

      var lists =document.getElementsByTagName(“ul”);

      var regexp = /\bdnd\b/;

      for(var i=0;i<lists.length;i++) if(regexp.text(list[i].className))dnd(lists[i]);

      //为列表元素添加拖放事件处理程序

      function dnd(list){

  var original_class = list.className; //保存原始css类

  var entered = 0;

   //当拖放对象首次进入列表时调用这个处理程序

   //它会检查拖放对象包含的数据格式它是否能处理

    //如果能,它返回false来表示有兴趣放置

   //这种情况下,它会高亮拖放目标,让用户知道兴趣

   list.ondragenter = function(e){

   e= e || window.event ;//标准或IE事件

   varfrom = e.relatedTarget;

   //dragenter和dragleave事件冒泡,它使得像<ul>元素有<li>子元素的情况下

    //何时高亮显示或取消高亮显示元素变得棘手,在定义relatedTarget的浏览器

   //中,我们能跟踪它,否则,我们需要通过统计进入和离开次数 如果从列表外进入

   //或第一次进入,那么需要做一些处理

    entered++;

    if((from &&!ischild(from,list)) || entered==1){

        var dt = e.dataTransfer; //所有dnd信息都在dataTransfer对象

         //dt.types对象列出可用的拖放数据的类型或格式

         //html5 定义这个对象有contains()方法

         //在一些浏览器中,它是一个有indexOf()方法的数组

         //在IE8及以前的版本中,它根本不存在

        var types = dt.types;

         //如果没有任何类型的数据或可用数据是纯文本格式

         //那么高亮显示列表让用户知道我们正在监听拖放

        //同时返回false让浏览器知晓

        if(!types || //ie

    (types.contains&& types.contains(“text/plain”)) || //html5

(types.indexOf && types. indexOf (“text/plain”)!=-1) //Webkit

 

){

 list.className = original_class+” droppable”;

 return false;

}

//如果我们无法识别数据类型,我们不希望拖放

return ;

}

return false ;//如果不是第一次进入,我们继续操持兴趣

}

//当鼠标指针悬停在列表上时,会调用这个处理程序

//我们必须定义这个处理程序并返回false,否则这个拖放操作将取消

 list.ondragover = function(e){return false;};

 list.ondragleave = function(e){

   e= e || window.event;

  var to = e.relatedTarget;

   entered--;

   if( to &&!ischild(to,list) || entered<=0){

        list.className = original_class;

        entered = 0;

}

return false;

};

list.ondrop = function(e){

     e= e || window.event;

    var dt = e.dataTransfer;

    var text = dt.getData(“Text”);

    if(text){

    var item = document.createElement(“li”);

    item.draggable = true;

    item.appendChild(document.createTextNode(text));

    list.appendChild(item);

    list.className = original_class;

    entered = 0;

    return false;

}

};

//使原始所有列表项可拖动

var items = list.getElementsByTagName(“li”);

for(var I =0;i<items.length;i++) items[i].draggable= true;

 

list.ondragstart = function(e){

    e=e|| window.event;

   var target =e.target || e.srcElement;

    if(target.tagName==”LI”)return false;

   var dt = e.dataTransfer;

    dt.setData(“Text”,target.innerText || target.textContent);

    dt.effectAllowed=”copyMove”;

};

list.ondragend = function(e){

        e= e|| window.event;

      var target =e.target || e.srcElement;

     if(e.dataTransfer.dropEffect===”move”)

target.parentNode.removeChild(“target”);

 

}

 

function ischild(a,b){

  for(; a;a=a.parentNode) if(a===b) return true;

  return false;

}

 

 

}

});

 

0 0