原文鏈接: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

