成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【詳】JS實(shí)現(xiàn)拖拽元素互換位置

lentrue / 1895人閱讀

摘要:只有在可放置的元素上面松開鼠標(biāo)才會(huì)觸發(fā)事件,所以這個(gè)是被放置的節(jié)點(diǎn)。

寫在前面的廢話

大家好,我是練習(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 - 用戶開始拖動(dòng)元素時(shí)觸發(fā)

ondrag - 元素正在拖動(dòng)時(shí)觸發(fā)

ondragend - 用戶完成元素拖動(dòng)后觸發(fā)

釋放拖拽元素時(shí)觸發(fā)的事件(松開鼠標(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ì)象離開其容器范圍內(nèi)時(shí)觸發(fā)此事件

ondrop - 在一個(gè)拖動(dòng)過(guò)程中,釋放鼠標(biāo)鍵時(shí)觸發(fā)此事件

我們來(lái)舉例子說(shuō)明一下

假設(shè)有div A和div B,當(dāng)我按住A,開始拖動(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中(并且放開鼠標(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)然你也可以自攻自受,就像孟德爾的自交豌豆一樣
我們下面做的拖拽也是自攻自受的情況,因?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事件。

開始操刀

這個(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. 我們先寫一個(gè)大概的樣式

2. html結(jié)構(gòu)如下

${title}

3. 開始寫邏輯,請(qǐng)仔細(xì)查看注釋

//先定義兩個(gè)變量來(lái)保存源元素,以及目標(biāo)元素,還有記錄一下上次交換的dom
//為什么要這一步呢?往后面看
let fromDom = null,
    toDom = null,
    lastDom = null;

//開始拖拽
function handleDragStart(e, dom) {
    //開始拖拽的時(shí)候,把來(lái)源保存下來(lái)
    fromDom = dom;
}
//拖拽中
function handleDrag(){
    console.log("如果你有業(yè)務(wù)邏輯的話,你可以寫,但是我沒有,抱歉")
}
//拖到了另一個(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)還沒有松開!
        //那么我又移動(dòng)到C,那么互換的位置就是B和C了,但是其實(shí)我一開始拖拽的是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è)不寫,無(wú)法交換div的innerHTML值,所以需要阻止默認(rèn)事件,這一步很重要!!
    e.preventDefault();
}

//放手
function handleDragEnd(e,dom){
    //拖拽時(shí)松開鼠標(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) {
    //只有在可放置的元素上面松開鼠標(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),主要的是 開始拖拽保存來(lái)源,進(jìn)入目標(biāo)時(shí),保存目標(biāo),并且經(jīng)過(guò)判斷后交換,交換完以后,我們就把目標(biāo)重置,完事~
邏輯比較簡(jiǎn)單,不過(guò)寫動(dòng)態(tài)css比較麻煩(因?yàn)槲覀冃枰恍ヽss的效果來(lái)分辨哪個(gè)是被你拖動(dòng)的,那個(gè)又互換了位置之類的,有比較好的用戶體驗(yàn)),剛開始寫經(jīng)常傻傻分不清是來(lái)源dom還是目標(biāo)dom~

辣雞源碼

此部分適合新手玩家,因?yàn)樽约褐皇请S意寫寫,并沒有寫得很規(guī)范,希望大家不要學(xué)習(xí)!





    
    



    
一些你可能不感興趣的后語(yǔ)

其實(shí)在沒有這個(gè)drag之前,是用鼠標(biāo)事件來(lái)實(shí)現(xiàn)的,這里就簡(jiǎn)單講講思路好了,懶得寫了~

注冊(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ō)了。

謝謝大家,希望大家寫代碼不要像cxk。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/54857.html

相關(guān)文章

  • JS實(shí)現(xiàn)拖拽元素互換位置

    摘要:只有在可放置的元素上面松開鼠標(biāo)才會(huì)觸發(fā)事件,所以這個(gè)是被放置的節(jié)點(diǎn)。 寫在前面的廢話 大家好,我是練習(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)...

    AaronYuan 評(píng)論0 收藏0
  • HTML5拖放API Drag and Drop

    摘要:此文研究中的拖放接口,提供各個(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ì)象和放置...

    dantezhao 評(píng)論0 收藏0
  • 前端基礎(chǔ)進(jìn)階(十):面向?qū)ο髮?shí)戰(zhàn)之封裝拖拽對(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í),這篇文章,...

    Eidesen 評(píng)論0 收藏0
  • 從GGEditor的一個(gè)案例看JS原生拖拽功能

    摘要:涉及部分的,不會(huì)對(duì)理解全局產(chǎn)生干擾。在上監(jiān)聽事件,當(dāng)為畫布時(shí),通過(guò)創(chuàng)建一個(gè)藍(lán)色虛線框移動(dòng)的時(shí)候,更新的位置在上監(jiān)聽事件,落在畫布時(shí),創(chuàng)建一個(gè)的節(jié)點(diǎn)從而完成整個(gè)拖拽添加元素的功能。 showImg(https://segmentfault.com/img/remote/1460000019564977);showImg(https://segmentfault.com/img/remot...

    PingCAP 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<