一些网友给我反馈,希望我给下详细的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的方法拖拽。我不会采用任何的库,而是用最原始的办法来实现,这将是最土鳖的方法,但是能体现拖动的原理。