摘要:只有在可放置的元素上面松開(kāi)鼠標(biāo)才會(huì)觸發(fā)事件,所以這個(gè)是被放置的節(jié)點(diǎn)。
寫(xiě)在前面的廢話
大家好,我是練習(xí)js時(shí)長(zhǎng)接近兩年半的個(gè)人練習(xí)生--李大雷
算了,直接 雞,你太美~
應(yīng)用場(chǎng)景很多時(shí)候,我們需要讓用戶來(lái)自定義自己想要的菜單順序,或者一些按鈕的排序,那么這個(gè)時(shí)候,怎么給用戶自定義順序呢?
拖拽無(wú)疑是最簡(jiǎn)單易懂的,因?yàn)橥孢^(guò)手機(jī)的都知道怎么拖動(dòng)桌面的app來(lái)改變位置。
那么要怎么做呢?最簡(jiǎn)單的方式肯定是用H5的拖放啦~
一些你需要了解的基礎(chǔ)知識(shí)首先我們先來(lái)看看,這兩個(gè)單詞,drag--拖,drop--放,從這里就很容易看出來(lái),這里的操作邏輯了。
我們來(lái)看看有哪些事件可以給我們使用。
被我們拖的元素(按住鼠標(biāo))
ondragstart - 用戶開(kāi)始拖動(dòng)元素時(shí)觸發(fā)
ondrag - 元素正在拖動(dòng)時(shí)觸發(fā)
ondragend - 用戶完成元素拖動(dòng)后觸發(fā)
釋放拖拽元素時(shí)觸發(fā)的事件(松開(kāi)鼠標(biāo))
ondragenter - 當(dāng)被鼠標(biāo)拖動(dòng)的對(duì)象進(jìn)入其容器范圍內(nèi)時(shí)觸發(fā)此事件
ondragover - 當(dāng)某被拖動(dòng)的對(duì)象在另一對(duì)象容器范圍內(nèi)拖動(dòng)時(shí)觸發(fā)此事件
ondragleave - 當(dāng)被鼠標(biāo)拖動(dòng)的對(duì)象離開(kāi)其容器范圍內(nèi)時(shí)觸發(fā)此事件
ondrop - 在一個(gè)拖動(dòng)過(guò)程中,釋放鼠標(biāo)鍵時(shí)觸發(fā)此事件
我們來(lái)舉例子說(shuō)明一下
假設(shè)有div A和div B,當(dāng)我按住A,開(kāi)始拖動(dòng)(A dragstart觸發(fā)一次)(drag在你移動(dòng)的時(shí)候不斷觸發(fā)),然后你經(jīng)過(guò)了B(B觸發(fā)了dragenter事件),然后你在B里瘋狂摩擦(那就瘋狂觸發(fā)B的dragover,這句話怎么越讀越不對(duì)勁?),然后你從B中出來(lái)(那就觸發(fā)了B的dragleave),然后又進(jìn)入B中(并且放開(kāi)鼠標(biāo),那么就會(huì)觸發(fā)B的drop和A的dragend);
對(duì)于A來(lái)說(shuō),它的事件就前面3個(gè),對(duì)于B來(lái)說(shuō),它的事件就是后面4個(gè);
A是攻,那么B就是受了。當(dāng)然你也可以自攻自受,就像孟德?tīng)柕淖越煌愣挂粯?/strong>
我們下面做的拖拽也是自攻自受的情況,因?yàn)槟憧赡芡蟿?dòng)A和B交換,也可能拖動(dòng)B來(lái)和A交換位置。
一些需要注意的點(diǎn):
如果只需要拖動(dòng)外層div,請(qǐng)務(wù)必把子元素的draggable屬性設(shè)置為false(如果子元素里面有默認(rèn)可拖動(dòng)元素,則需要把里面的可拖動(dòng)元素的屬性設(shè)置為false);不然會(huì)引起很多奇怪的現(xiàn)象(比如你想拖一個(gè)包含圖片的div,結(jié)果只把圖片拖出來(lái)了);
鏈接和圖片是默認(rèn)可以拖動(dòng)的;
ondragenter和ondragleave可能會(huì)觸發(fā)多次,如果你把A拖動(dòng)到B里,B一個(gè)大div設(shè)置了enter和leave事件,但是它里面還有很多子div,那么每進(jìn)出一個(gè)子div,都會(huì)觸發(fā)一次enter和leave事件。
開(kāi)始操刀這個(gè)標(biāo)題的cao是第一聲。
經(jīng)過(guò)我們上面的一頓基礎(chǔ)知識(shí)學(xué)習(xí)以后呢,我們就很容易想清楚這個(gè)實(shí)現(xiàn)邏輯。
把A設(shè)置為可以拖動(dòng),當(dāng)A拖動(dòng)到B的時(shí)候,我們就互換A和B兩個(gè)dom節(jié)點(diǎn)。
至于怎么互換呢?我們可以直接調(diào)換兩個(gè)節(jié)點(diǎn)的內(nèi)容,或者我們調(diào)換兩個(gè)dom節(jié)點(diǎn)的位置兩種方法,這里我用的是第一種方法,第二種留給大家去嘗試?yán)瞺
1. 我們先寫(xiě)一個(gè)大概的樣式
2. html結(jié)構(gòu)如下
${title}![]()
3. 開(kāi)始寫(xiě)邏輯,請(qǐng)仔細(xì)查看注釋
//先定義兩個(gè)變量來(lái)保存源元素,以及目標(biāo)元素,還有記錄一下上次交換的dom //為什么要這一步呢?往后面看 let fromDom = null, toDom = null, lastDom = null; //開(kāi)始拖拽 function handleDragStart(e, dom) { //開(kāi)始拖拽的時(shí)候,把來(lái)源保存下來(lái) fromDom = dom; } //拖拽中 function handleDrag(){ console.log("如果你有業(yè)務(wù)邏輯的話,你可以寫(xiě),但是我沒(méi)有,抱歉") } //拖到了另一個(gè)div中,這個(gè)時(shí)候的dom就是另一個(gè)元素了哦 function handleDragEnter(e, dom) { //保存目標(biāo)元素 toDom = dom; if(fromDom == lastDom){ //第一次調(diào)換 //為什么要分為幾次調(diào)換位置呢? //想一下,如果我剛A和B調(diào)換了位置,那么就是B和A了但是此時(shí)我的鼠標(biāo)還沒(méi)有松開(kāi)! //那么我又移動(dòng)到C,那么互換的位置就是B和C了,但是其實(shí)我一開(kāi)始拖拽的是A,我只想換AC只是不小心路過(guò)了B! //因此我們這里就要使用一個(gè)lastDom來(lái)記錄上次路過(guò)交換的DOM,同時(shí)也要區(qū)分第幾次調(diào)換。 swapDom(lastDom, toDom); //記錄新的‘上一個(gè)dom’ lastDom = toDom; }else{ //這個(gè)防止enter多次觸發(fā) if(lastDom == toDom){return;} //第N+1次調(diào)換,要先把上一個(gè)div的東西還原回去,再跟第三個(gè)div互換 swapDom(fromDom,lastDom); swapDom(fromDom,toDom); //記錄新的‘上一個(gè)dom’ lastDom = toDom; } } //在B中移動(dòng) function handleDragOver(e, dom) { //默認(rèn)無(wú)法把元素放置到其他元素當(dāng)中,如果這個(gè)不寫(xiě),無(wú)法交換div的innerHTML值,所以需要阻止默認(rèn)事件,這一步很重要??! e.preventDefault(); } //放手 function handleDragEnd(e,dom){ //拖拽時(shí)松開(kāi)鼠標(biāo)就會(huì)會(huì)觸發(fā)dragend事件,這個(gè)dom是拖拽的節(jié)點(diǎn)。 //重置toDom,下次拖拽就是新拖拽了,fromDom和lastDom會(huì)在dragStart的時(shí)候重置 toDom = null; } //有上面那個(gè),其實(shí)這個(gè)可以省略了。 function handleDrop(e, dom) { //只有在可放置的元素上面松開(kāi)鼠標(biāo)才會(huì)觸發(fā)drop事件,所以這個(gè)dom是被放置的dom節(jié)點(diǎn)。 //重置toDom,下次拖拽就是新拖拽了,fromDom和lastDom會(huì)在dragStart的時(shí)候重置 toDom = null; } //交換dom內(nèi)容 function swapDom(from, to) { let temp = a.innerHTML; a.innerHTML = b.innerHTML; b.innerHTML = temp; }總結(jié)
其實(shí)我們用不上那么多事件回調(diào),主要的是 開(kāi)始拖拽保存來(lái)源,進(jìn)入目標(biāo)時(shí),保存目標(biāo),并且經(jīng)過(guò)判斷后交換,交換完以后,我們就把目標(biāo)重置,完事~
邏輯比較簡(jiǎn)單,不過(guò)寫(xiě)動(dòng)態(tài)css比較麻煩(因?yàn)槲覀冃枰恍ヽss的效果來(lái)分辨哪個(gè)是被你拖動(dòng)的,那個(gè)又互換了位置之類的,有比較好的用戶體驗(yàn)),剛開(kāi)始寫(xiě)經(jīng)常傻傻分不清是來(lái)源dom還是目標(biāo)dom~
此部分適合新手玩家,因?yàn)樽约褐皇请S意寫(xiě)寫(xiě),并沒(méi)有寫(xiě)得很規(guī)范,希望大家不要學(xué)習(xí)!
一些你可能不感興趣的后語(yǔ)
其實(shí)在沒(méi)有這個(gè)drag之前,是用鼠標(biāo)事件來(lái)實(shí)現(xiàn)的,這里就簡(jiǎn)單講講思路好了,懶得寫(xiě)了~
注冊(cè)mousedown事件,
在mousedown觸發(fā)的時(shí)候注冊(cè)mousemove事件,根據(jù)鼠標(biāo)移動(dòng)的位置來(lái)定位點(diǎn)擊的dom,也就是讓這個(gè)元素跟著你的鼠標(biāo)移動(dòng)(你的dom得絕對(duì)定位哦),這里比較麻煩的就是一些邊界的判定,因?yàn)槟愕氖髽?biāo)能到邊界,但是你的div不一定可以(div面積比較大),而且根據(jù)業(yè)務(wù)不同,你也可能有不同的操作,這里因人而異啦~
在mousedown里也注冊(cè)mouseup事件,mouseup的作用就是把mousemove事件清空,因?yàn)橐恳淮问髽?biāo)按下去的時(shí)候才能有mousemove事件。
至于交換的話,上面也有說(shuō)了。
謝謝大家,希望大家寫(xiě)代碼不要像cxk。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/103318.html
摘要:只有在可放置的元素上面松開(kāi)鼠標(biāo)才會(huì)觸發(fā)事件,所以這個(gè)是被放置的節(jié)點(diǎn)。 寫(xiě)在前面的廢話 大家好,我是練習(xí)js時(shí)長(zhǎng)接近兩年半的個(gè)人練習(xí)生--李大雷 算了,直接 雞,你太美~ 應(yīng)用場(chǎng)景 很多時(shí)候,我們需要讓用戶來(lái)自定義自己想要的菜單順序,或者一些按鈕的排序,那么這個(gè)時(shí)候,怎么給用戶自定義順序呢?拖拽無(wú)疑是最簡(jiǎn)單易懂的,因?yàn)橥孢^(guò)手機(jī)的都知道怎么拖動(dòng)桌面的app來(lái)改變位置。 那么要怎么做呢?最簡(jiǎn)...
摘要:此文研究中的拖放接口,提供各個(gè)屬性和方法的說(shuō)明,解決拖放過(guò)程中的拖拽數(shù)據(jù)對(duì)象存儲(chǔ)和獲取問(wèn)題。方法增加一個(gè)拖拽數(shù)據(jù)對(duì)象到屬性中,并返回增加的拖拽數(shù)據(jù)對(duì)象。若拖拽數(shù)據(jù)對(duì)象是文本字符串類型,通過(guò)回調(diào)函數(shù)獲取拖拽數(shù)據(jù)中的字符串?dāng)?shù)據(jù)。 此文研究Web API中的拖放接口,提供各個(gè)屬性和方法的說(shuō)明,解決拖放過(guò)程中的拖拽數(shù)據(jù)對(duì)象存儲(chǔ)和獲取問(wèn)題。 拖放API作用到兩個(gè)目標(biāo)對(duì)象,分別是拖拽目標(biāo)對(duì)象和放置...
摘要:前面幾篇文章,我跟大家分享了的一些基礎(chǔ)知識(shí),這篇文章,將會(huì)進(jìn)入第一個(gè)實(shí)戰(zhàn)環(huán)節(jié)利用前面幾章的所涉及到的知識(shí),封裝一個(gè)拖拽對(duì)象。不封裝對(duì)象直接實(shí)現(xiàn)利用原生封裝拖拽對(duì)象通過(guò)擴(kuò)展來(lái)實(shí)現(xiàn)拖拽對(duì)象。 showImg(https://segmentfault.com/img/remote/1460000008699587); 前面幾篇文章,我跟大家分享了JavaScript的一些基礎(chǔ)知識(shí),這篇文章,...
摘要:涉及部分的,不會(huì)對(duì)理解全局產(chǎn)生干擾。在上監(jiān)聽(tīng)事件,當(dāng)為畫(huà)布時(shí),通過(guò)創(chuàng)建一個(gè)藍(lán)色虛線框移動(dòng)的時(shí)候,更新的位置在上監(jiān)聽(tīng)事件,落在畫(huà)布時(shí),創(chuàng)建一個(gè)的節(jié)點(diǎn)從而完成整個(gè)拖拽添加元素的功能。 showImg(https://segmentfault.com/img/remote/1460000019564977);showImg(https://segmentfault.com/img/remot...
閱讀 1384·2021-11-15 11:45
閱讀 3153·2021-09-27 13:36
閱讀 2894·2019-08-30 15:54
閱讀 1011·2019-08-29 12:38
閱讀 2938·2019-08-29 11:22
閱讀 3012·2019-08-26 13:52
閱讀 2060·2019-08-26 13:30
閱讀 616·2019-08-26 10:37