HTML5原生拖放实例分析

Posted 最骚的就是你

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HTML5原生拖放实例分析相关的知识,希望对你有一定的参考价值。

原文链接:http://www.cnblogs.com/zhenwen/p/5855107.html

HTML5提供了原生拖放功能的javascript API,使用起来很方便。

兼容性:

 

对于PC端浏览器,Firefox、Chrome、Safari支持良好,而IE和Edge浏览器有些特性不支持,如IE10和IE11、Edge对于dataTransfer.setData(format,data) ,只定义了"text"和"URL"两种有效的数据类型。而HTML5规范允许支持各种MIME类型。

详细参考这里: http://caniuse.com/#search=drag

 

本文实现HTML5原生拖放的应用Demo,用到了常用的方法和属性,兼容现代浏览器,还是先看效果:

 

 下面详细介绍——

原生拖放事件:

应用于被拖动元素的事件:

  • dragstart

    按下鼠标并开始移动鼠标,会在被拖放的元素上触发dragstart事件。

    注意:要使用HTML5的原生拖放功能,使该元素可拖动,需要设置draggable属性。默认情况下,图像、链接和被选中的文本是可以拖动的,因为它们的draggable属性已经自动被设置成true。

    

  • drag

    触发dragstart事件后,随即会触发drag事件,而且在元素被拖动期间会持续触发该事件。

  • dragend

    拖动停止(放开鼠标)的时候,会触发dragend事件。

 

应用于放置目标的事件:

  • dragenter

    只要有元素被拖动到放置目标上,就会触发dragenter事件。

  • dragover

    触发dragenter事件后,随即会触发dragover事件,而且只要被拖动元素在放置目标的范围内移动时,就会持续触发。

  • dragleave

    元素被拖出了放置目标,dragover事件不再发生,但会触发dragleave事件。

  • drop

    元素被放到了放置目标中,则会触发drop事件,而不是dragleave事件。

 

  注意:(1)被拖动元素和放置目标可以设置为同一个元素,在自身上也可以触发drop事件,虽然好像没啥用 =。=

     (2)被拖动元素进入放置目标范围和离开的参考标准是鼠标的位置,而不是鼠标下面拖动着的图像的边界

                 (3)拖动时显示在鼠标光标下方的图像,默认是该元素的一个副本,在dragstart事件中对完成对元素的复制(也可以通过setDragImage()自定义鼠标下拖动的元素),因此要隐藏本来的元素,最好在drag事件中处理,就是在复制后进行处理(参见文末的源代码)

 

dataTransfer对象

  dataTransfer对象是事件对象的一个属性,只能在拖放事件的事件处理程序中访问。而且,dataTransfer对象的一些方法和属性也只能在特定的拖放事件中进行设置。

  常用方法:

  • setData(format,data)

    在dragstart事件中,针对被拖放元素调用setData()函数,设置要传递的数据;用于从被拖放元素向放置目标传递字符串格式的数据。

   第一个参数是数据类型,其中IE只定义了"text"和"URL"两种有效的数据类型;第二个参数是字符串,表示要传递的数据。  

 

  • getData(format)

    在drop事件中,针对放置目标调用getData()函数,取得传递过来的数据。

     第一个参数是setData( )中设置的数据类型

 

  • setDragImage(element, x, y)

    指定一副图像,当拖动发生的时候,显示在光标的下方。接受3个参数: 要显示的HTML元素和光标在图像中的x,y坐标。其中HTML元素可以是一幅图像,也可以是其他元素。

     该属性IE10、IE11、Edge浏览器不支持。

 

  • clearData(format)

     清除以特定格式保存的数据。

 

  常用属性:

  • dropEffect

  在dragenter事件中处理程序中,针对放置目标设置dropEffect属性的值,决定被拖动的元素能够执行哪种放置行为(同时被拖动元素拖到放置目标上时,会显示不一样的光标符号)

    none:不能把拖动的元素放在这里。这是除了文本框之外所有元素默认的值。

    move:应该把拖动的元素移动到放置目标。

    copy:应该把拖动的元素复制到放置目标。

    link:放置目标会打开拖动的元素(但拖动的元素必须是个链接,有URL地址)。

  

  • effectAllowed

  在dragstart事件处理程序中,针对被拖放元素设置effectAllowed属性的值,表示允许拖动元素的哪种dropEffect,和上面的dropEffect属性搭配使用。

    uninitialized:没有给被拖动元素设置任何放置行为。

    none:被拖动的元素不能有任何行为。

    copy:只允许值为"copy"的dropEffect。

    link:只允许值为"link"的dropEffect。

    move:只允许值为"move"的dropEffect。

    copyLink:允许值为"copy"和"link"的dropEffect。

    copyMove:允许值为"copy"和"move"的dropEffect。

    linkMove:允许值为"link"和"move"的dropEffect。

    all:允许任意dropEffect。

 

   关于dataTransfer其他的一些方法和属性,以及更详细的介绍,请看这里  https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API

 

文末源码部分——

HTML代码:

<div id=\'container\'>
<div id=\'wrap\'>
<img src="http://d3.freep.cn/3tb_160909012718ljdh572240.jpg" title=\'鞋子\'/>
<img src="http://d2.freep.cn/3tb_160909012718973d572240.jpg" title=\'包子\'/>
<img src="http://d2.freep.cn/3tb_1609090127197ux5572240.jpg" title=\'薯片\'/>
</div>
<div id=\'cart\'></div>
</div>

CSS代码:

*{
margin: 0;
padding: 0;
}
body{
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#wrap{
height: 100px;
text-align: center;
}
img{
width: 100px;
height: 100px;
cursor: -webkit-grab;
cursor: -moz-grab;
cursor: grab;
}
#cart{
width: 500px;
height: 100px;
border-radius: 20px;
margin: 50px auto 0;
background-color: orange;
}
#cart.hover{
background-color: red;
}
#cart img{
width: 70px;
height: 70px;
margin: 15px;
}


复制代码
*{
    margin: 0;
    padding: 0;
}
body{
    -webkit-user-select: none; 
       -moz-user-select: none; 
       -ms-user-select: none; 
       user-select: none;
}
#wrap{
    height: 100px;
    text-align: center;
}
img{
    width: 100px;
    height: 100px;
    cursor: -webkit-grab;
    cursor: -moz-grab;
    cursor: grab;
}
#cart{
    width: 500px;
    height: 100px;
    border-radius: 20px;
    margin: 50px auto 0;
    background-color: orange;
}
#cart.hover{
    background-color: red;
}
#cart img{
    width: 70px;
    height: 70px;
    margin: 15px;
}
复制代码

JS代码:

//被拖动元素的三个事件
function dragstart(e){
e = EventUtil.getEvent(e);
var target = EventUtil.getTarget(e);
e.dataTransfer.setData("text",target.title);
//因为IE10、IE11和Edge不支持setDragImage()方法,需要判断
if(e.dataTransfer.setDragImage){
e.dataTransfer.setDragImage(target,50,50);
}

//effectAllowed事件和dropEffect事件搭配使用
e.dataTransfer.effectAllowed = \'move\';
dragElement = target;
}
function drag(e){
e = EventUtil.getEvent(e);
var target = EventUtil.getTarget(e);
setOpacity(target,0);
}
function dragend(e){
e = EventUtil.getEvent(e);
var target = EventUtil.getTarget(e);
setOpacity(target,1);
}

//放置目标的四个事件
function dragenter(e){
e = EventUtil.getEvent(e);
var target = EventUtil.getTarget(e);
//重要!重写dragenter事件的默认行为,使其可以触发drop事件
EventUtil.preventDefault(e);
//dropEffect事件和effectAllowed事件搭配使用
e.dataTransfer.dropEffect = \'move\';
target.className = \'hover\';
}
function dragover(e){
e = EventUtil.getEvent(e);
//重要!重写dragover事件的默认行为,使其可以触发drop事件
EventUtil.preventDefault(e);
}
function dragleave(e){
e = EventUtil.getEvent(e);
var target = EventUtil.getTarget(e);
target.className = \'\';
}
function drop(e){
e = EventUtil.getEvent(e);
var target = EventUtil.getTarget(e);
var title = e.dataTransfer.getData("text");
console.warn(\'把%s添加到购物车中!\',title);
target.className = \'\';
dragElement.parentNode.removeChild(dragElement);
var img = dragElement.cloneNode();
img.draggable = false;
setOpacity(img,1);
cart.appendChild(img);

//重要!为了让Firefox支持正常的拖放,取消drop事件的默认行为
EventUtil.preventDefault(e);
}


//设置透明度
function setOpacity(element,value){
if(typeof element.style.opacity!=\'undefined\'){
element.style.opacity=value;
}else{
element.style.filter = "alpha(opacity="+value*100+")";
}
}
//事件处理,做兼容处理
var EventUtil={
//添加事件处理程序
addHandler:function(element,type,handler){
if(element.addEventListener){
element.addEventListener(type,handler,false);
}else if(element.attachEvent){
element.attachEvent("on"+type,handler);
}else{
element["on"+type]=handler;
}
},
//获取事件对象
getEvent:function(event){
return event?event:window.event;
},
//获取事件的目标
getTarget:function(event){
return event.target||event.srcElement;
},
//取消默认事件
preventDefault:function(event){
if(event.preventDefault){
event.preventDefault();
}else{
event.returnValue=false;
}
}
};

var imgs = document.getElementsByTagName("img"),
cart = document.getElementById(\'cart\'),
dragElement = null;

for(var i=0; i<imgs.length; i++ ){
EventUtil.addHandler(imgs[i],\'dragstart\',dragstart);
EventUtil.addHandler(imgs[i],\'drag\',drag);
EventUtil.addHandler(imgs[i],\'dragend\',dragend);
}
EventUtil.addHandler(cart,\'dragenter\',dragenter);
EventUtil.addHandler(cart,\'dragover\',dragover);
EventUtil.addHandler(cart,\'dragleave\',dragleave);
EventUtil.addHandler(cart,\'drop\',drop);


复制代码
//被拖动元素的三个事件
function dragstart(e){
  e = EventUtil.getEvent(e);
  var target = EventUtil.getTarget(e);
  e.dataTransfer.setData("text",target.title);
  //因为IE10、IE11和Edge不支持setDragImage()方法,需要判断
  if(e.dataTransfer.setDragImage){
    e.dataTransfer.setDragImage(target,50,50); 
  }
  
  //effectAllowed事件和dropEffect事件搭配使用
  e.dataTransfer.effectAllowed = \'move\';
  dragElement = target;
}
function drag(e){
  e = EventUtil.getEvent(e);
  var target = EventUtil.getTarget(e);
  setOpacity(target,0);
}
function dragend(e){
  e = EventUtil.getEvent(e);
  var target = EventUtil.getTarget(e);
  setOpacity(target,1);
}

//放置目标的四个事件
function dragenter(e){
  e = EventUtil.getEvent(e);
  var target = EventUtil.getTarget(e);
  //重要!重写dragenter事件的默认行为,使其可以触发drop事件
  EventUtil.preventDefault(e); 
  //dropEffect事件和effectAllowed事件搭配使用
  e.dataTransfer.dropEffect = \'move\';
  target.className = \'hover\';
}
function dragover(e){
  e = EventUtil.getEvent(e);
  //重要!重写dragover事件的默认行为,使其可以触发drop事件
  EventUtil.preventDefault(e); 
}
function dragleave(e){
  e = EventUtil.getEvent(e);
  var target = EventUtil.getTarget(e);
  target.className = \'\';
}
function drop(e){
  e = EventUtil.getEvent(e);
  var target = EventUtil.getTarget(e);
  var title = e.dataTransfer.getData("text");
  console.warn(\'把%s添加到购物车中!\',title);
  target.className = \'\';
  dragElement.parentNode.removeChild(dragElement);
  var img = dragElement.cloneNode();
  img.draggable = false;
  setOpacity(img,1);
  cart.appendChild(img);

  //重要!为了让Firefox支持正常的拖放,取消drop事件的默认行为
  EventUtil.preventDefault(e); 
}


//设置透明度
function setOpacity(element,value){
  if(typeof element.style.opacity!=\'undefined\'){
    element.style.opacity=value;
  }else{
    element.style.filter = "alpha(opacity="+value*100+")";        
  }
}
//事件处理,做兼容处理
var EventUtil={    
  //添加事件处理程序
  addHandler:function(element,type,handler){     
    if(element.addEventListener){          
      element.addEventListener(type,handler,false);    
    }else if(element.attachEvent){           
      element.attachEvent("on"+type,handler);      
    }else{         
      element["on"+type]=handler;           
    }   
  },      
  //获取事件对象
  getEvent:function(event){       
    return event?event:window.event;   
  },     
  //获取事件的目标
  getTarget:function(event){      
    return event.target||event.srcElement;   
  },    
  //取消默认事件
  preventDefault:function(event){       
    if(event.preventDefault){         
      event.preventDefault();       
    }else{         
      event.returnValue=false;      
    }   
  }
};

var imgs = document.getElementsByTagName("img"),
    cart = document.getElementById(\'cart\'),
    dragElement = null;

for(var i=0; i<imgs.length; i++ ){
  EventUtil.addHandler(imgs[i],\'dragstart\',dragstart);
  EventUtil.addHandler(imgs[i],\'drag\',drag);
  EventUtil.addHandler(imgs[i],\'dragend\',dragend);
}
EventUtil.addHandler(cart,\'dragenter\',dragenter);
EventUtil.addHandler(cart,\'dragover\',dragover);
EventUtil.addHandler(cart,\'dragleave\',dragleave);
EventUtil.addHandler(cart,\'drop\',drop);
复制代码

参考资料: 《JavaScript高级程序设计》,MDN

以上是关于HTML5原生拖放实例分析的主要内容,如果未能解决你的问题,请参考以下文章

Html5 的拖拽功能

使用 HTML5 原生拖放时如何约束移动?

是否可以在拖动时更改光标图标,使用 HTML5 原生拖放

HTML5 拖放 - 没有透明度?

深入理解javascript原生拖放

拖动原始元素 HTML5 拖放