拖拽效果的實現原理分析


  一些網友給我反饋,希望我給下詳細的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的方法拖拽。我不會采用任何的庫,而是用最原始的辦法來實現,這將是最土鱉的方法,但是能體現拖動的原理。

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM