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