HTML5提供了原生拖放功能的JavaScript API,使用起來很方便。web
兼容性:瀏覽器
對於PC端瀏覽器,Firefox、Chrome、Safari支持良好,而IE和Edge瀏覽器有些特性不支持,如IE10和IE十一、Edge對於dataTransfer.setData(format,data) ,只定義了"text"和"URL"兩種有效的數據類型。而HTML5規範容許支持各類MIME類型。app
詳細參考這裏: http://caniuse.com/#search=dragide
本文實現HTML5原生拖放的應用Demo,用到了經常使用的方法和屬性,兼容現代瀏覽器,仍是先看效果:函數
下面詳細介紹——spa
原生拖放事件:設計
應用於被拖動元素的事件:3d
按下鼠標並開始移動鼠標,會在被拖放的元素上觸發dragstart事件。code
注意:要使用HTML5的原生拖放功能,使該元素可拖動,須要設置draggable屬性。默認狀況下,圖像、連接和被選中的文本是能夠拖動的,由於它們的draggable屬性已經自動被設置成true。orm
觸發dragstart事件後,隨即會觸發drag事件,並且在元素被拖動期間會持續觸發該事件。
拖動中止(放開鼠標)的時候,會觸發dragend事件。
應用於放置目標的事件:
只要有元素被拖動到放置目標上,就會觸發dragenter事件。
觸發dragenter事件後,隨即會觸發dragover事件,並且只要被拖動元素在放置目標的範圍內移動時,就會持續觸發。
元素被拖出了放置目標,dragover事件再也不發生,但會觸發dragleave事件。
元素被放到了放置目標中,則會觸發drop事件,而不是dragleave事件。
注意:(1)被拖動元素和放置目標能夠設置爲同一個元素,在自身上也能夠觸發drop事件,雖然好像沒啥用 =。=
(2)被拖動元素進入放置目標範圍和離開的參考標準是鼠標的位置,而不是鼠標下面拖動着的圖像的邊界
(3)拖動時顯示在鼠標光標下方的圖像,默認是該元素的一個副本,在dragstart事件中對完成對元素的複製(也能夠經過setDragImage()自定義鼠標下拖動的元素),所以要隱藏原本的元素,最好在drag事件中處理,就是在複製後進行處理(參見文末的源代碼)
dataTransfer對象
dataTransfer對象是事件對象的一個屬性,只能在拖放事件的事件處理程序中訪問。並且,dataTransfer對象的一些方法和屬性也只能在特定的拖放事件中進行設置。
經常使用方法:
在dragstart事件中,針對被拖放元素調用setData()函數,設置要傳遞的數據;用於從被拖放元素向放置目標傳遞字符串格式的數據。
第一個參數是數據類型,其中IE只定義了"text"和"URL"兩種有效的數據類型;第二個參數是字符串,表示要傳遞的數據。
在drop事件中,針對放置目標調用getData()函數,取得傳遞過來的數據。
第一個參數是setData( )中設置的數據類型
指定一副圖像,當拖動發生的時候,顯示在光標的下方。接受3個參數: 要顯示的HTML元素和光標在圖像中的x,y座標。其中HTML元素能夠是一幅圖像,也能夠是其餘元素。
該屬性IE十、IE十一、Edge瀏覽器不支持。
清除以特定格式保存的數據。
經常使用屬性:
在dragenter事件中處理程序中,針對放置目標設置dropEffect屬性的值,決定被拖動的元素可以執行哪一種放置行爲(同時被拖動元素拖到放置目標上時,會顯示不同的光標符號)
none:不能把拖動的元素放在這裏。這是除了文本框以外全部元素默認的值。
move:應該把拖動的元素移動到放置目標。
copy:應該把拖動的元素複製到放置目標。
link:放置目標會打開拖動的元素(但拖動的元素必須是個連接,有URL地址)。
在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; }
JS代碼:
//被拖動元素的三個事件 function dragstart(e){ e = EventUtil.getEvent(e); var target = EventUtil.getTarget(e); e.dataTransfer.setData("text",target.title); //由於IE十、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