拖拽效果的实现原理分析

  一些网友给我反馈,希望我给下详细的demo,其实我觉得学习知识还是要自己动手,亲身实践下才体会深刻,顾没有提供可以使用的demo给大家直接下载下来看效果了,但是为了大家对我的期望,后面写的一些文章,如有必要,我都会给大家提供demo,供大家参考的。

  好了,进入正题,经常在网站上看到各种拖动的效果,很酷,如,百度新首页,接下来我来分析下拖动到底是什么实现的。

一、html5现在已经提供支持拖动和拖放的API了,所以,支持html5的浏览器可以不必折腾了,直接使用吧。

  关于html5的拖拽api 请查看http://dev.w3.org/html5/spec/dnd.html 

 以下摘录一些 比较重要的对象和事件以及属性

* 首先,要使元素能否能被拖拽,必须设置 draggable  = "true"  例如:<div  draggable =“true”>只有设置draggable才可以被拖拽</div>

* 一个很很重要的接口 DataTransfer,它是拖拽对象用来传递的媒介,它包含以下属性和方法

  • dataTransfer.dropEffect [ = value ]:返回已选择的拖放效果,如果该操作效果与起初设置的effectAllowed效果不符,则拖拽操作失败。可以设置修改,包含这几个值:“none”, “copy”, “link” 和 “move”
  • dataTransfer.effectAllowed [ = value ]:返回允许执行的拖拽操作效果,可以设置修改,包含这些值:“none”, “copy”, “copyLink”, “copyMove”, “link”, “linkMove”, “move”, “all” 和 “uninitialized”
  • dataTransfer.types:返回在dragstart事件出发时为元素存储数据的格式,如果是外部文件的拖拽,则返回”files”
  • dataTransfer.clearData ( [ format ] ):删除指定格式的数据,如果未指定格式,则删除当前元素的所有携带数据
  • dataTransfer.setData(format, data):为元素添加指定数据
  • dataTransfer.getData(format):返回指定数据,如果数据不存在,则返回空字符串
  • dataTransfer.files:如果是拖拽文件,则返回正在拖拽的文件列表FileList
  • dataTransfer.setDragImage(element, x, y):制定拖拽元素时跟随鼠标移动的图片,x、y分别是相对于鼠标的坐标(据测试,Chrome暂不支持)
  • dataTransfer.addElement(element):添加一起跟随拖拽的元素,如果你想让某个元素跟随被拖拽元素一同被拖拽,则使用此方法(据测试,Chrome暂不支持)

Drag & Drop 包括以下事件:

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

注意:在ondragover中一定要执行preventDefault(),否则ondrop事件不会被触发。另外,如果是从其他应用软件或是文件中拖东西进来,尤其是图片的时候,默认的动作是显示这个图片或是相关信息,并不是真的执行drop。此时需要用用document的ondragover事件把它直接干掉。

下面我们来模拟一个购物车,将各种东西拖进到购物车里面去。

首先看一个截图

可以将商品往购物车里面拖动,当然你可以将购物车的东西拖出来。代码如下,里面都做了注释了,分析已经很详细了。

<!DOCTYPE html >
<html >
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gbk" />
<title>购物车DEMO</title>
<style>
.mod-buy
{width:800px;margin:0 auto;}
.mod-buy .inBox
{width:600px; height:160px; line-height:1.5;border:1px solid #dfdfdf;margin-bottom:10px}
.mod-buy .outBox
{width:500px; height:150px; padding-left:20px;border:1px solid #dfdfdf;}
.mod-buy .list
{ width:80px;float:left;height:30px;line-height:30px; margin:5px; border:2px dashed #444;
background-color
:#ddd; cursor:move;}
.mod-buy .list:hover
{border-color:#666; background-color:#888;}

</style>
</head>

<body>
<div class="mod-buy">
<h3>购物车</h3>
<div class="inBox"> </div>
<h3>商品信息</h3>
<div class="outBox">

<div class="list" title="物品1" draggable="true">物品1</div>
<div class="list" title="物品2" draggable="true">物品2</div>
<div class="list" title="物品3" draggable="true">物品3</div>
<div class="list" title="物品4" draggable="true">物品4</div>
<div class="list" title="物品5" draggable="true">物品5</div>
<div class="list" title="物品6" draggable="true">物品6</div>
<div class="list" title="物品7" draggable="true">物品7</div>
<div class="list" title="物品8" draggable="true">物品8</div>
<div class="list" title="物品9" draggable="true">物品9</div>
<div class="list" title="物品10" draggable="true">物品10</div>
<div class="list" title="物品11" draggable="true">物品11</div>
</div>
</div>
<script>

(
function(){

var $ = function(selector,tag) {
if (!selector) { return []; }
var arrElement = [];
if (document.querySelectorAll) {
arrElement
= document.querySelectorAll(selector);
}
else {
var all = document.getElementsByTagName(tag);
for (var i = 0,len = all.length; i<len; i++) {
if (/^\./.test(selector)) {
if (all[i].className === selector.replace(".", "")) {
arrElement.push(all[i]);
}
}
else if(/^/.test(selector)) {
if (all[i].id === selector) {
arrElement.push(all[i]);
}
}
}
}
return arrElement;
};

var inBox = $(".inBox","div")[0],
outBox
= $(".outBox","div")[0],
dragsEle
= $("div",".list"),
dragLen
= dragsEle.length,
eleDrag
= null;
//为拖拽的元素绑定事件
for (var i=0; i<dragLen; i+=1) {
//使拖拽的元素不能选定
dragsEle[i].onselectstart = function() {
return false;
};
//该元素开始拖动的时候
dragsEle[i].ondragstart = function(ev) {
ev.dataTransfer.effectAllowed
= "move";
ev.dataTransfer.setData(
"text", ev.target.innerHTML);
ev.dataTransfer.setDragImage(ev.target,
10, 10);
eleDrag
= ev.target;
return true;
};
//该对象结束拖动的时候
dragsEle[i].ondragend = function(ev) {
ev.dataTransfer.clearData(
"text");
eleDrag
= null;
return false
};
}
//拖动该对象到目标对象上移动的时候
inBox.ondragover = function(ev) {
ev.preventDefault();
return true;
};
//进入目标对象的时候
inBox.ondragenter = function(ev) {
return true;
};
//放开手的时候
inBox.ondrop = function(ev) {
if (eleDrag) {
var tmp = eleDrag;
eleDrag.parentNode.removeChild(eleDrag);
this.appendChild(tmp);
}
return false;
};
outBox.ondragover
= function(ev) {
ev.preventDefault();
return true;
};

outBox.ondragenter
= function(ev) {

return true;
};
outBox.ondrop
= function(ev) {
if (eleDrag) {
var tmp = eleDrag;
eleDrag.parentNode.removeChild(eleDrag);
this.appendChild(tmp);
}
return false;
};
})();


</script>
</body>
</html>

下文再继续讲解不支持html5的方法拖拽。我不会采用任何的库,而是用最原始的办法来实现,这将是最土鳖的方法,但是能体现拖动的原理。

  

原文地址:https://www.cnblogs.com/yupeng/p/2404427.html