目錄:
- 用H5方法實現拖拽交互
- 自定義事件
- 自定義拖拽事件
- 實現兼容所有瀏覽器的拖拽交互
跟着教程用H5實現了一個簡單的拖拽,左右兩個白盒子是容器,兩邊的紅盒子可以任意拖拽。
滿足以下兩個要求:
- 被拖起來的盒子變成黃色,並且在原容器中消失,跟隨鼠標移動。
- 被拖拽的盒子進入容器時,容器會變顏色,離開時恢復原來的顏色。
- 拖拽釋放后,添加到准確的位置。
HTML+CSS為:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>拖動</title> </head> <style> body{ background-color: #ccc; } .container { width: 200px; height: 800px; background-color: #fff; border: 1px solid #000; margin: 50px; float: left; } .box { width: 200px; height: 80px; background-color: #f00; border: 1px solid #000; } .light { background-color: #f9f; } .move { background-color: #ffff73; } .hide { display: none; } </style> <body> <div class="wrap"> <div class="container"> <div class="box">1</div> <div class="box">2</div> <div class="box">3</div> <div class="box">4</div> </div><!--container結束--> <div class="container"> <div class="box">5</div> <div class="box">6</div> <div class="box">7</div> </div><!--container結束--> </div><!--wrap結束-->
<script type="text/javascript" src="js/util.js"></script>
<script type="text/javascript" src="js/dragAnddrop.js"></script> </body> </html>
(util.js中是一些平時經常會用到的方法,像下面會出現的$.on( )用於接受一個選擇器,然后在其表示的節點上綁定事件。$.getElements( )負責選出符合接收到的選擇器的所有元素。)
看教程之前,我的代碼大致是這樣的:
window.onload=function(){ var boxes=getElements(".box"); //設置拖動目標可以被拖動 each(me.box,function(item,index){ item.draggable=true; }); //獲取拖動目標,並為其添加樣式 $.on(".wrap","dragstart",function(e){ var e=e||window.event, target=e.target||e.srcElement; if (hasClass(target,"box")) { e.dataTransfer.setData("text/plain",".move"); } }); //其他功能 }
然后我看到了教程中這樣的代碼:
(function () { var dnd = { // 初始化 init: function () { var me = this; me.src = document.querySelector('#demo1-src'); me.panelList = document.querySelector('.panel-list'); // 為拖拽源監聽dragstart,設置關聯數據 me.src.addEventListener('dragstart', me.onDragStart, false); //省略 onDragStart: function (e) { e.dataTransfer.setData('text/plain', 'demo1-src'); }, //省略 dnd.init(); }());
頓時覺得自己寫了一坨屎。不過還好,終於見識到了傳說中的面向對象。
在用H5實現拖拽交互的過程中,我遇到一個問題:
為drop添加事件處理程序的時候,要用appendChild方法將被拖拽的盒子添加到容器中去,那么要怎么獲取到被拖拽的元素呢?
我先想到可以在dragstart事件處理程序中把被拖拽的元素保存在一個變量里,然后再drop的事件處理程序訪問它。但是很遺憾,並不能訪問到。想一想,這是因為變量被聲明之后的值是undefined,他在dragstart事件處理程序中被賦值,結束之后這個值就已經失效了,所以drop的事件處理程序中訪問到的變量值是undefined。
然后我想到了,在事件處理程序中想要獲得信息,可以通過傳入的事件對象,想到這里,之前看的雲里霧里的dataTransfer對象就派上用場了。可以在dragstart事件處理程序中將為被拖拽的對象添加的class通過setData()方法傳遞給drop,這樣就可以獲取到他了。
最終寫好的代碼如下:
window.onload=function(){ var dragdrop={ //初始化 init:function(){ var me=this; me.box=getElements(".box"); //設置拖動目標可以被拖動 each(me.box,function(item,index){ item.draggable=true; }); //獲取拖動目標,並為其添加樣式 $.on(".wrap","dragstart",me.dragStart); //讓拖動目標在拖起來的時候在原容器中消失 $.on(".wrap","drag",me.Drag); //松開的時候恢復原狀 $.on(".wrap","dragend",me.dragEnd); //監聽放置目標的dragenter事件,添加視覺效果 $.on(".wrap","dragenter",me.dragEnter); //設置放置目標 $.on(".wrap","dragover",me.prevent); //取消視覺效果 $.on(".wrap","dragleave",me.dragLeave); //在拖放目標上處理 $.on(".wrap","drop",me.dragDrop); }, dragStart:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (hasClass(target,"box")) { e.dataTransfer.setData("text/plain",".move"); addClass(target,"move"); } }, Drag:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (hasClass(target,"box")) { addClass(target,"hide"); } }, dragEnd:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (hasClass(target,"box")) { removeClass(target,"hide"); removeClass(target,"move"); } }, dragEnter:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (hasClass(target,"container")) { addClass(target,"light"); } }, prevent:function(e){ $.prevent(e); }, dragLeave:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (hasClass(target,"container")) { removeClass(target,"light"); } }, dragDrop:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (hasClass(target,"container")) { var dragging=$(e.dataTransfer.getData("text/plain")); removeClass(dragging,"move"); removeClass(target,"light"); target.appendChild(dragging); } }, } dragdrop.init(); }
雖然還沒有很深刻的體會到這種面向對象寫法的好處,但還是模仿着寫了。
接下來就要開始照顧不支持H5的寶寶們了。
一開始就被一系列的問題卡住,他怎么動起來?什么時候讓他動起來?怎么讓他跟着鼠標走?他怎么回去?怎么給它綁定事件處理程序?
前兩個問題還能勉強想出來,當鼠標按下的時候,可以給他設置position:absolute讓他動起來,然后讓他的left和top和mousedown事件的鼠標坐標相同就可以了。
后幾個問題就真的束手無策了。
在《JavaScript高級程序設計》中找到答案,發現這件事情真的沒那么簡單。
最本質的,要深刻地理解事件是怎么回事。
事件是一種叫做觀察者的設計模式,這是一種創建松散耦合代碼的技術。對象可以發布事件,用來表示在該對象生命周期中某個有趣的時刻到了。然后其他對象可以觀察該對象,等待這些有趣的時刻到來並通過運行代碼來響應。
意思就是說,事件是一個對象發出的信號,他邀請別人一起來慶祝他重要的時刻,不管有沒有人願意來,他都可以發出信號。
那么,他要怎樣發出信號呢? 通過 函數調用 很容易就可以實現對象之間的通信。
有行為就需要有管理機制,得到一個名字,檢測其對應的函數,執行函數。所以就需要一個對象來進行管理。
函數的調用需要一些代碼,需要函數名。所以這個對象中應該保存着函數名表示事件類型,還要保存該類型相應的代碼,所以他還需要一個個方法為其添加事件類型和處理函數,還要有一個讓函數中的代碼執行的方法,這個方法讀取函數名,然后執行這個函數名對應的代碼。可以添加就要可以刪除,所以還需要一個負責刪除處理程序的方法。
所以,這個對象應該長這樣:
{
事件類型和他的代碼們:
{type1:[fun1,fun2...]
type2:[fun1,fun2,..]
.....}
接待員:為對象添加type和相應fun。
執行官:接收一個type執行相應代碼。
清理員:接收一個type和他想刪除的fun,為其刪掉這個fun。
}
用JavaScript實現就長下面這樣:
function eventTarget(){ this.handlers={}; } eventTarget.prototype={ constructor:eventTarget, addHandler:function(type,handler){ if (typeof this.handlers[type]=="undefined") { this.handlers[type]=[]; } this.handlers[type].push(handler); }, fire:function(e){ var handlers=this.handlers[e.type] if (isArray(handlers)) { for (var i = 0,len = handlers.length;i<len; i++) { handlers[i](e); } } }, removeHandler:function(type,handler){ if (isArray(this.handlers[type])) { removeItem(this.handlers[type],handler); } }, };
用這種構造函數+原型的方式,就是為了自定義的事件可以繼承他的方法,並擁有自己的事件類型。
有了這個完美的事件管理機制,就可以自定義拖拽事件對象了。
按照H5的思路,他應該可以觸發這6種事件:dragstart、drag、dragend、dragenter、dragleave和drop。
首先,他如何觸發dragstart?什么時候應該觸發dragstart?
拖拽的本質就是,鼠標在一個元素上按下不松開,挪動鼠標,放到另一個地方,松開。
聽起來好像很熟悉,就是我們熟悉的mousedown、mousemove和mouseup嘛。
所以,當元素上發生mousedown的時候,就觸發dragstart事件,移動的時候觸發drag,移動到目標元素里面的時候觸發dragenter,移出去的時候觸發dragleave,松開的時候要是在目標元素里面就觸發drop,然后觸發dragend(因為不在里面的話要回到原位)。
如果要綁定事件的話,就要知道綁定在哪里,因為事先不知道要被綁定的元素,所以綁定在document上,讓每個DOM對象都有機會成為被拖拽的和放置目標。然后指定篩選條件,在指定的滿足條件的對象上面觸發事件。
那么,如何指定被拖拽對象和放置目標呢?
還是模仿H5,他通過設置draggable屬性和阻止瀏覽器默認行為,我們也可以通過添加一個自定義屬性或者類名,來判別目標對象。
想明白這些之后,就可以開始寫處理程序了,解決了重重問題之后,最后的對象是這樣的:
//自定義拖動事件(和HTML的class屬性耦合) var DragDrop=function(){ var dragdrop=new eventTarget(), dragging=null, x=0,y=0, border_r,border_l,border_top,border_btm, left,right,top,bottom; function handle(e){ var e=e||window.event, target=e.target||e.srcElement, drops=getElements(".dropable"); //問題1 switch(e.type){ case "mousedown": if (hasClass(target,"draggable")) { dragging=target; x=e.clientX-target.offsetLeft; y=e.clientY-target.offsetTop; dragdrop.fire({ type:"dragstart", target:dragging, x:e.clientX, y:e.clientY }); } break; case "mousemove": if (dragging!==null) { dragging.style.left=e.clientX-x+"px"; dragging.style.top=e.clientY-y+"px"; dragdrop.fire({ type:"drag", target:dragging, x:e.clientX, y:e.clientY }); if (drops[0]) { for (var i = 0; i < drops.length; i++) { border_l=dragging.offsetLeft; border_r=parseInt(getCSS(dragging,"width"))+border_l; //問題2 border_top=dragging.offsetTop; border_btm=parseInt(getCSS(dragging,"height"))+border_top; left=drops[i].offsetLeft; right=parseInt(getCSS(drops[i],"width"))+left; top=drops[i].offsetTop; bottom=parseInt(getCSS(drops[i],"height"))+top; if(border_r>left&&border_l<right&&border_top<bottom&&border_btm>top){ dragdrop.fire({ type:"dragenter", target:drops[i] }); }else{ dragdrop.fire({ type:"dragleave", target:drops[i] }); } } } } break; case "mouseup": if (drops[0]&&dragging) { for (var i = 0; i < drops.length; i++) { dragWidth=parseInt(getCSS(dragging,"width")); border_r=dragWidth+dragging.offsetLeft; border_l=dragging.offsetLeft; left=drops[i].offsetLeft; right=drops[i].offsetLeft+parseInt(getCSS(drops[i],"width")); if(border_r>left&&border_l<right&&border_top<bottom&&border_btm>top){ //問題3 dragdrop.fire({ type:"drop", target:drops[i], dragging:dragging }); break; } } } dragdrop.fire({ type:"dragend", target:dragging, x:e.clientX, y:e.clientY }); dragging=null; break; } }; dragdrop.enable=function(){ $.add(document,"mousedown",handle); $.add(document,"mousemove",handle); $.add(document,"mouseup",handle); }; dragdrop.disable=function(){ $.remove(document,"mousedown",handle); $.remove(document,"mousemove",handle); $.remove(document,"mouseup",handle); }; return dragdrop; }
問題1:
最開始的時候,我是不知道該怎么將被拖拽對象和目標對象分開的,我一直想,當感受到拖拽的時候就讓事件的target變成被拖拽的元素,當感受到有東西改過來時讓事件的target變成目標對象,當我嘗試着把dragenter事件讓mouseenter來觸發時,失望的發現,鼠標上拖着東西的時候是無法觸發mouseenter的。
然后我想到,既然只能獲得被拖拽的對象,也沒有想mousedown那樣的事件可以來獲取放置目標,那就換個思路。通過class來獲取,畢竟在我心中class是個萬能的東西。所以我的邏輯就是,獲取到所有class=droppable的對象,判斷他們是否被拖動元素覆蓋,是的話就觸發dragenter,不是的話就觸發dragleave。(這也就導致了問題3。)
問題2:
我想到的判斷拖拽元素是否在目標元素上方的方法是,看被拖動元素是否有兩條邊線在目標元素之內。這就需要獲取拖拽元素和目標元素的width。
而用node.style.width獲取不到。查了一下發現,這個方法只能獲取到寫在標簽里面的樣式。想要獲取CSS中的樣式,需要用DOM2級樣式中定義的document.defaultView.getComputerStyle()和IE的obj.currentStyle。所以就寫了一個getCSS方法,代碼如下:
//獲得元素的CSS樣式 function getCSS(ele,name){ if (ele) { return document.defaultView.getComputedStyle? document.defaultView.getComputedStyle(ele,null)[name]:ele.currentStyle[name]; } }
問題3:
由於我上面判斷目標對象的邏輯,被拖拽的元素會更容易drop進第一個帶有droppable的容器里面。這個問題還有待解決。
定義好拖拽事件對象之后,就可以為其綁定處理程序了。
這時候就體現出之前面向對象寫法的好處了:①他將所有事件處理函數都變成對象自身的方法,減少了很多游離再全局中的變量。②這些方法只有他自己能調用,外部不需要知道這里會發生什么,只需要知道他能做這些事情就夠了。
這樣的寫法,讓一切變得非常井然有序,邏輯清晰。
因為他們處理的方法是不同的,所以事件處理程序中的執行代碼會有些差異,需要判斷一下,不然會有沖突。
到這里,已經可以實現我想要的功能了,而且還沒有發現什么重大的問題。所以暫時先寫成這個樣子啦。
雖然一直很嫌棄不支持新方法的瀏覽器,尤其是IE。但是這次要好好的感謝一下他,讓我更深刻的了解了事件,並且讓我見識到了JavaScript如此強大的函數,它可以創造無限可能。
完整代碼(https://github.com/mamengyi/Baidu/tree/master/2015_Spring/task0002/%E6%8B%96%E6%8B%BD%E4%BA%A4%E4%BA%92)
//自定義事件 function eventTarget(){ this.handlers={}; } eventTarget.prototype={ constructor:eventTarget, addHandler:function(type,handler){ if (typeof this.handlers[type]=="undefined") { this.handlers[type]=[]; } this.handlers[type].push(handler); }, fire:function(e){ var handlers=this.handlers[e.type] if (isArray(handlers)) { for (var i = 0,len = handlers.length;i<len; i++) { handlers[i](e); } } }, removeHandler:function(type,handler){ if (isArray(this.handlers[type])) { removeItem(this.handlers[type],handler); } }, }; //自定義拖動事件(和HTML的class屬性耦合) var DragDrop=function(){ var dragdrop=new eventTarget(), dragging=null, x=0,y=0, border_r,border_l,border_top,border_btm, left,right,top,bottom; function handle(e){ var e=e||window.event, target=e.target||e.srcElement, drops=getElements(".dropable"); switch(e.type){ case "mousedown": if (hasClass(target,"draggable")) { dragging=target; x=e.clientX-target.offsetLeft; y=e.clientY-target.offsetTop; dragdrop.fire({ type:"dragstart", target:dragging, x:e.clientX, y:e.clientY }); } break; case "mousemove": if (dragging!==null) { dragging.style.left=e.clientX-x+"px"; dragging.style.top=e.clientY-y+"px"; dragdrop.fire({ type:"drag", target:dragging, x:e.clientX, y:e.clientY }); if (drops[0]) { for (var i = 0; i < drops.length; i++) { border_l=dragging.offsetLeft; border_r=parseInt(getCSS(dragging,"width"))+border_l; border_top=dragging.offsetTop; border_btm=parseInt(getCSS(dragging,"height"))+border_top; left=drops[i].offsetLeft; right=parseInt(getCSS(drops[i],"width"))+left; top=drops[i].offsetTop; bottom=parseInt(getCSS(drops[i],"height"))+top; if(border_r>left&&border_l<right&&border_top<bottom&&border_btm>top){ dragdrop.fire({ type:"dragenter", target:drops[i] }); }else{ dragdrop.fire({ type:"dragleave", target:drops[i] }); } } } } break; case "mouseup": if (drops[0]&&dragging) { for (var i = 0; i < drops.length; i++) { dragWidth=parseInt(getCSS(dragging,"width")); border_r=dragWidth+dragging.offsetLeft; border_l=dragging.offsetLeft; left=drops[i].offsetLeft; right=drops[i].offsetLeft+parseInt(getCSS(drops[i],"width")); if(border_r>left&&border_l<right&&border_top<bottom&&border_btm>top){ //會更容易drop進第一個盒子里。 dragdrop.fire({ type:"drop", target:drops[i], dragging:dragging }); break; } } } dragdrop.fire({ type:"dragend", target:dragging, x:e.clientX, y:e.clientY }); dragging=null; break; } }; dragdrop.enable=function(){ $.add(document,"mousedown",handle); $.add(document,"mousemove",handle); $.add(document,"mouseup",handle); }; dragdrop.disable=function(){ $.remove(document,"mousedown",handle); $.remove(document,"mousemove",handle); $.remove(document,"mouseup",handle); }; return dragdrop; } //拖動 window.onload=function(){ var dragdrop={ //初始化 inith5:function(){ var me=this; me.box=getElements(".box"); //設置拖動目標可以被拖動 each(me.box,function(item,index){ item.draggable=true; }); //獲取拖動目標,並為其添加樣式 $.on(".wrap","dragstart",me.dragStart); //讓拖動目標在拖起來的時候在原容器中消失 $.on(".wrap","drag",me.Drag); //松開的時候恢復原狀 $.on(".wrap","dragend",me.dragEnd); //監聽放置目標的dragenter事件,添加視覺效果 $.on(".wrap","dragenter",me.dragEnter); //設置放置目標 $.on(".wrap","dragover",me.prevent); //取消視覺效果 $.on(".wrap","dragleave",me.dragLeave); //在拖放目標上處理 $.on(".wrap","drop",me.dragDrop); }, init:function(){ var me=this, dragevent=new DragDrop(); dragevent.enable(); //設置拖動目標可以被拖動 me.box=getElements(".box"); each(me.box,function(item,index){ addClass(item,"draggable"); }); //獲取拖動目標,並為其添加樣式 dragevent.addHandler("dragstart",me.dragStart); //松開的時候恢復原狀 dragevent.addHandler("dragend",me.dragEnd); //監聽放置目標的dragenter事件,添加視覺效果 dragevent.addHandler("dragenter",me.dragEnter); //設置放置目標 me.container=getElements(".container"); each(me.container,function(item,index){ addClass(item,"dropable"); }); //取消視覺效果 dragevent.addHandler("dragleave",me.dragLeave); //在拖放目標上處理 dragevent.addHandler("drop",me.dragDrop); }, dragStart:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (hasClass(target,"box")) { if (e.dataTransfer) { e.dataTransfer.setData("text/plain",".move"); addClass(target,"move"); }else{ addClass(target,"moving"); } } }, Drag:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (e.dataTransfer&&hasClass(target,"box")) { addClass(target,"hide"); } }, dragEnd:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (e.dataTransfer&&hasClass(target,"box")) { removeClass(target,"hide"); removeClass(target,"move"); }else{ removeClass(target,"moving"); } }, dragEnter:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (hasClass(target,"container")) { addClass(target,"light"); } }, prevent:function(e){ $.prevent(e); }, dragLeave:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (hasClass(target,"container")) { removeClass(target,"light"); } }, dragDrop:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (e.dataTransfer&&hasClass(target,"container")) { var dragging=$(e.dataTransfer.getData("text/plain")); removeClass(dragging,"move"); removeClass(target,"light"); target.appendChild(dragging); }else if (e.dragging) { var lights=getElements(".light"), len=lights.length; for (var i = 0; i < len; i++) { removeClass(lights[0],"light"); //注意這里是一個NodeList } removeClass(e.dragging,"moving"); target.appendChild(e.dragging); } }, } if(supportDrag()){ dragdrop.inith5(); }else{ dragdrop.init(); } }
util:
//對數組(類數組對象)的每項都執行fn(item,index) function each(arr,fn){ for(var i = 0 , len = arr.length ; i<len ; i++){ fn(arr[i],i); } } //DOM元素選擇器 function getElements(selector){ //類選擇器,返回全部項 if(/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/.test(selector)){ if(document.getElementsByClassName){ return document.getElementsByClassName(selector.slice(1,selector.length)); } var nodes = document.all ? document.all : document.getElementsByTagName('*'); var arr=[];//用來保存符合的className; for(var i=0;i<nodes.length;i++){ if(hasClass(nodes[i],selector.slice(1,selector.length))){ arr.push(nodes[i]); } } return arr; } //ID選擇器 if(/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/.test(selector)){ return document.getElementById(selector.slice(1,selector.length)); } //tag選擇器 if(/^((?:[\w\u00c0-\uFFFF\-]|\\.)+)/.test(selector)){ return document.getElementsByTagName(selector); } //屬性選擇器 if(/^\[[A-Za-z0-9_-\S]+\]$/.test(selector)){ selector = selector.slice(1,selector.length-1); var eles = document.getElementsByTagName("*"); selector = selector.split("="); var att = selector[0]; var value = selector[1]; var arr = []; if (value) { for (var i = 0; i < eles.length; i++) { if(eles[i].getAttribute(att)==value){ arr.push(eles[i]); } } }else{ for (var i = 0; i < eles.length; i++) { if(eles[i].getAttribute(att)){ arr.push(eles[i]); } } } return arr; } } function $(selector){ var all=selector.split(/\s+/); var result = [],rooot=[document]; for (var i = 0; i < all.length; i++) { var type=all[i][0]; switch(type){ //ID case "#" : for (var j = 0; j < rooot.length; j++) { var ele=rooot[j].getElementById(all[i].slice(1)); if (ele) { result.push(ele); } } break; //class case ".": for (var j = 0; j < rooot.length; j++) { if (document.getElementsByClassName) { var eles=rooot[j].getElementsByClassName(all[i].slice(1)); if (eles) { result=result.concat(Array.prototype.slice.call(eles)); } }else{ var arr = rooot[j].getElementsByTagName("*"); for (var i = 0; i < arr.length; i++) { if (hasClass(arr[i], className)) { result.push(arr[i]); } } } } break; //屬性 case "[": var att = all[i].slice(1,all[i].length-1).split("="); var key = att[0],value=att[1]; for (var j = 0; j < rooot.length; j++) { var eles=rooot[j].getElementsByTagName("*"); for (var i = 0; i < eles.length; i++) { if (value) { for (var i = 0; i < eles.length; i++) { if(eles[i].getAttribute(key)==value){ result.push(eles[i]); } } }else{ for (var i = 0; i < eles.length; i++) { if(eles[i].getAttribute(key)){ result.push(eles[i]); } } } } } break; //tag default: for (var j = 0; j < rooot.length; j++) { eles=rooot[j].getElementsByTagName(all[i]); if (eles) { result=result.concat(Array.prototype.slice.call(eles)); } } } rooot=result; result=[]; } return rooot[0]; } //檢查ele是否有className function hasClass(ele,className){ if (ele&&ele.className) { var classes=ele.className.split(/\s+/);//這里必須要切成數組之后再判斷 if(classes.indexOf(className)!=-1){ return true; } } return false; } // 為element增加一個樣式名為newClassName的新樣式 function addClass(ele,newClass){ if (!hasClass(ele,newClass)) { ele.className=ele.className?[ele.className,newClass].join(" "):newClass; } } // 移除element中的樣式oldClassName function removeClass(ele,oldClass){ if (hasClass(ele,oldClass)) { var arr = ele.className.split(/\s+/); for (var i = 0; i < arr.length; i++) { if(arr[i]===oldClass){ arr.splice(i,1); break; } } ele.className=arr.join(" "); } } //獲得元素的CSS樣式 function getCSS(ele,name){ if (ele) { return document.defaultView.getComputedStyle? document.defaultView.getComputedStyle(ele,null)[name]:ele.currentStyle[name]; } } //添加事件 function addEvent(selector,event,listener){ var ele=$(selector); if(ele.addEventListener){ ele.addEventListener(event,listener,false); }else{ ele.attachEvent("on"+event,listener); } } //添加事件(給節點) function addEventToNode(ele,event,listener){ if(ele.addEventListener){ ele.addEventListener(event,listener,false); }else{ ele.attachEvent("on"+event,listener); } } //移除事件 function removeEvent(selector,event,listener){ var ele=$(selector); if(ele.removeEventListener){ ele.removeEventListener(event,listener,false); }else{ ele.detachEvent("on"+event,listener); } } function removeNodeEvent(ele,event,listener){ if(ele.removeEventListener){ ele.removeEventListener(event,listener,false); }else{ ele.detachEvent("on"+event,listener); } }
//阻止瀏覽器默認行為
function preventDefault(e){
if (e&&e.preventDefault) {
e.preventDefault();
}else{
e.returnValue=false;
}
return false;
}
$.prevent=preventDefault;
$.on = addEvent; $.add = addEventToNode; $.un = removeEvent; $.remove=removeNodeEvent;
//判斷是否支持ondrag事件
function supportDrag(){
var div = document.createElement('div');
return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div);
}
參考:
教程:http://qiudeqing.com/html5/2015/05/17/drag-and-drop.html