基于JavaScript 實(shí)現(xiàn)拖放功能
HTML 的拖放 API 依賴 DOM 事件模型,獲取拖放和放置元素的相關(guān)信息,以此實(shí)現(xiàn)拖放功能。我們只需要注冊(cè)很少幾個(gè)事件監(jiān)聽(tīng)器,就能把任何元素變成可拖動(dòng)或可放置的。
拖放 API 除了提供基本的拖放功能接口外,還可以在拖放之外提供選擇,用來(lái)自定義行為。比如,可以修改拖放元素的 CSS 樣式?;蛘?,我們不移動(dòng)元素,拖動(dòng)的時(shí)候,復(fù)制一個(gè)副本,拖放結(jié)束后,我們就會(huì)多了一個(gè)同樣的元素。
本篇只介紹實(shí)現(xiàn)基本的拖放功能。
將元素設(shè)置成可拖動(dòng)的
我們先從拖動(dòng)元素開(kāi)始。假設(shè)我們有一個(gè)容器元素,其中包含兩種類型的子元素:可拖動(dòng)元素和可放置元素。舉個(gè)例子,如果我們有一個(gè)待辦事項(xiàng)列表,我們可以將待辦事項(xiàng)拖到“完成”區(qū)域。
簡(jiǎn)單起見(jiàn),我們將移動(dòng)的元素稱為拖動(dòng)元素,將拖動(dòng)元素移入的目標(biāo)元素稱為 dropzone。
<div class='parent'> <span id='draggableSpan'> draggable </span> <span> dropzone </span> </div>

這是我們的第一段代碼,子元素現(xiàn)在還 不能 拖動(dòng)。
下面給拖動(dòng)元素添加屬性 draggable='true' ,將它設(shè)置成一個(gè)可拖動(dòng)元素。
<div class='parent'> <span id='draggableSpan' draggable='true'> draggable </span> <span> dropzone </span> </div>

現(xiàn)在你再用鼠標(biāo)拖動(dòng)拖動(dòng)元素的時(shí)候,它就會(huì)跟隨鼠標(biāo)移動(dòng)(對(duì)不起,移動(dòng)端不行:see_no_evil:)。
draggable 屬性在沒(méi)設(shè)置的情況下,默認(rèn)值 auto 。就是說(shuō),元素是可不可以拖動(dòng),取決于瀏覽器的默認(rèn)設(shè)置。比如,鏈接( <a> )默認(rèn)就是可拖動(dòng)的,而 <span> 就不是。
拖放事件處理器
到目前為止,如果我們拖動(dòng)元素,釋放鼠標(biāo),什么事都不會(huì)發(fā)生。拖動(dòng)和放置都會(huì)觸發(fā)事件,實(shí)現(xiàn)一個(gè)基本的拖放功能,我們最少需要用到拖放 API 中的三個(gè)事件:
ondragstart
ondragover
ondrop
學(xué)會(huì)使用 ondragstart 、 ondragover 、 ondrop 事件只是個(gè)開(kāi)始。拖拽過(guò)程一共會(huì)涉及八個(gè)事件: ondrag 、 ondragend 、 ondragenter 、 ondragexit 、 ondragleave 、 ondragover 、 ondragstart 和 ondrop 。
DataTransfer
DataTransfer 接口中保存了與當(dāng)前拖放過(guò)程相關(guān)的跟蹤信息,信息從 DataTransfer 對(duì)象屬性中獲得,而 DataTransfer 對(duì)象又是從 DOM 事件對(duì)象中獲得的。
技術(shù)上講, DataTransfer 接口可以同時(shí)跟蹤多個(gè)拖動(dòng)對(duì)象的信息,我們這里只關(guān)注拖動(dòng)一個(gè)元素的情況。:sparkles:
拖動(dòng)時(shí)更新元素
下一步,我們開(kāi)始設(shè)置 ondragstart 的事件處理器。
拖動(dòng)開(kāi)始時(shí),我們可以在 ondragstart 處理器中,做任何想做的修改。比如更新拖動(dòng)元素的 CSS 樣式,將拖動(dòng)的版本設(shè)置為臨時(shí)圖片,或者其他能從 DOM 事件中訪問(wèn)到的任何內(nèi)容。
dataTransfer 對(duì)象的 setData 屬性可以用來(lái)設(shè)置拖動(dòng)狀態(tài)信息。它接收兩個(gè)參數(shù),第一個(gè)參數(shù)是表示內(nèi)容格式的字符串,第二個(gè)參數(shù)是實(shí)際傳遞的數(shù)據(jù)。
我們要實(shí)現(xiàn)的功能是將拖動(dòng)元素移動(dòng)到一個(gè)新的父元素里面。我們需要獲取拖動(dòng)元素,因此需要將拖動(dòng)元素的 ID 通過(guò) setData 屬性保存下來(lái):
function onDragStart(event) {
event
.dataTransfer
.setData('text/plain', event.target.id);
}
再?gòu)氖录?duì)象中獲得拖動(dòng)元素并設(shè)置 CSS 樣式:
function onDragStart(event) {
event
.dataTransfer
.setData('text/plain', event.target.id);
event
.currentTarget
.style
.backgroundColor = 'yellow';
}
注意:如果上面的黃色背景樣式,你只希望在拖動(dòng)時(shí)才應(yīng)用,那么拖動(dòng)結(jié)束后,就要手動(dòng)將樣式恢復(fù)。就會(huì)說(shuō),拖動(dòng)開(kāi)始時(shí),如果修改了元素樣式,除非再次修改過(guò)來(lái),否則樣式是不會(huì)自動(dòng)恢復(fù)的。:rainbow:
拖動(dòng)開(kāi)始時(shí)的處理函數(shù)寫(xiě)好了,現(xiàn)在將它設(shè)置給可拖動(dòng)元素的 ondragstart 屬性:
<div class='parent'> <span id='draggableSpan' draggable='true' ondragstart='onDragStart(event);'> draggable </span> <span> dropzone </span> </div>
下面是使用鼠標(biāo)拖動(dòng)時(shí)的效果:

現(xiàn)在拖動(dòng)元素, ondragstart 中的代碼就會(huì)執(zhí)行,樣式改變了,但釋放拖動(dòng)元素后,什么事情都沒(méi)發(fā)生。接下來(lái)我們將視線轉(zhuǎn)移到 dropzone 上來(lái)。
設(shè)置元素為可放置的
ondragstart 之后,下一個(gè)要寫(xiě)的處理函數(shù)就是 ondragover 了。上面講過(guò),放置行為默認(rèn)是被瀏覽器阻止的,我們需要取消這個(gè)默認(rèn)行為,雙重否定為肯定,對(duì)吧?
function onDragOver(event) {
event.preventDefault();
}
在阻止瀏覽器干擾后,現(xiàn)在就能將拖動(dòng)元素添加到 dropzone 了,dropzone 成為能夠接受任何拖動(dòng)元素的容器元素。
<div class='parent'> <span id='draggableSpan' draggable='true' ondragstart='onDragStart(event);'> draggable </span> <span ondragover='onDragOver(event);'> dropzone </span> </div>
即便現(xiàn)在 dropzone 可以接受拖動(dòng)元素,釋放鼠標(biāo)后還是看不見(jiàn)改變發(fā)生。
放置的時(shí)候要做什么?
現(xiàn)在要介紹第三個(gè)也是最后一個(gè)處理函數(shù) ondrop 。
我們的函數(shù)邏輯遵循以下步驟:
- 還記得在
setData中設(shè)置的數(shù)據(jù)嗎? - 現(xiàn)在我們需要從
dataTransfer對(duì)象的getData屬性中獲取設(shè)置的數(shù)據(jù),數(shù)據(jù)內(nèi)容是拖動(dòng)元素的 ID,它會(huì)返回給我們。 - 使用上一步獲取的 ID,獲得拖動(dòng)元素。 獲取 dropzone 元素。
- 將拖拽元素 append 到 dropzone 中。
- 清理 dataTransfer 對(duì)象中保存的數(shù)據(jù)。
function onDrop(event) {
const id = event
.dataTransfer
.getData('text');
const draggableElement = document.getElementById(id);
const dropzone = event.target;
dropzone.appendChild(draggableElement);
event
.dataTransfer
.clearData();
}
因?yàn)檫@是我們要寫(xiě)的第三個(gè)也是最后一個(gè)函數(shù),我們只要將它傳遞給 dropzone 的 ondrop 屬性,就完成了一個(gè)完整的拖放功能!
<div class='parent'> <span id='draggableSpan' draggable='true' ondragstart='onDragStart(event);'> draggable </span> <span ondragover='onDragOver(event);' ondrop='onDrop(event);'> dropzone </span> </div>

這里寫(xiě)的示例是最基本的,它展示如何使頁(yè)面上的任何內(nèi)容可變得可拖動(dòng)。當(dāng)然,一個(gè)網(wǎng)頁(yè)里可以同時(shí)包含多個(gè)可拖動(dòng)元素、多個(gè) dropzone,或者使用文本沒(méi)有介紹的其他事件做更加細(xì)粒度的自定義設(shè)置。
下面展示的是本文一開(kāi)始提到的那個(gè)簡(jiǎn)單的待辦事項(xiàng)列表功能。:fire:

只要依據(jù)本文上面已經(jīng)講過(guò)的內(nèi)容,稍微變通一下,就能寫(xiě)出來(lái)。只要確保這里可拖動(dòng)待辦項(xiàng)目的 ID 是唯一的就行了。
總結(jié)
以上所述是小編給大家介紹的基于JavaScript 實(shí)現(xiàn)拖放功能,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺(jué)得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
相關(guān)文章
js實(shí)現(xiàn)點(diǎn)擊文本框顯示日期選擇器特效代碼分享
這篇文章主要為大家詳細(xì)介紹了javascript實(shí)現(xiàn)點(diǎn)擊文本框顯示日期選擇器特效,提高了工作效率,推薦給大家,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2015-08-08
一文解決前端JS小數(shù)運(yùn)算精度問(wèn)題
在做項(xiàng)目的時(shí)候,前端需要在表格的底部做一個(gè)匯總的功能,在采用reduce對(duì)當(dāng)前屬性所有值匯總時(shí),發(fā)現(xiàn)匯總結(jié)果存在好長(zhǎng)的小數(shù)位,本文給大家介紹了如何解決前端JS小數(shù)運(yùn)算精度問(wèn)題,需要的朋友可以參考下2024-02-02
javaScript中一些常見(jiàn)的數(shù)據(jù)類型檢查校驗(yàn)
最近在面試的時(shí)候又被問(wèn)到JS中檢查校驗(yàn)數(shù)據(jù)類型的方法,所以這篇文章主要給大家介紹了關(guān)于javaScript中一些常見(jiàn)的數(shù)據(jù)類型檢查校驗(yàn)的相關(guān)資料,需要的朋友可以參考下2022-05-05
JavaScript中防抖和節(jié)流的原理和區(qū)別詳解
JavaScript 中,防抖和節(jié)流是一種用于優(yōu)化事件處理函數(shù)調(diào)用頻率的技術(shù),防抖和節(jié)流的目的都是為了避免頻繁地觸發(fā)事件處理函數(shù),從而減少瀏覽器和服務(wù)器的負(fù)擔(dān),本文將給大家介紹一下JavaScript中防抖和節(jié)流的原理和區(qū)別,需要的朋友可以參考下2023-09-09
微信小程序?qū)崿F(xiàn)自動(dòng)播放視頻模仿gif動(dòng)圖效果實(shí)例
這篇文章主要給大家介紹了關(guān)于微信小程序?qū)崿F(xiàn)自動(dòng)播放視頻模仿gif動(dòng)圖效果的相關(guān)資料,通過(guò)本文介紹的方法可以實(shí)現(xiàn)自動(dòng)播放視頻,視頻無(wú)控制條無(wú)聲音且自動(dòng)循環(huán)播放,需要的朋友可以參考下2021-07-07
js時(shí)鐘翻牌效果實(shí)現(xiàn)代碼分享
這篇文章主要介紹了javascript時(shí)鐘翻牌效果的實(shí)現(xiàn),效果非??犰牛瑢?shí)現(xiàn)步驟也很簡(jiǎn)單,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2015-08-08

