基于JavaScript 實(shí)現(xiàn)拖放功能
HTML 的拖放 API 依賴 DOM 事件模型,獲取拖放和放置元素的相關(guān)信息,以此實(shí)現(xiàn)拖放功能。我們只需要注冊(cè)很少幾個(gè)事件監(jiān)聽器,就能把任何元素變成可拖動(dòng)或可放置的。
拖放 API 除了提供基本的拖放功能接口外,還可以在拖放之外提供選擇,用來(lái)自定義行為。比如,可以修改拖放元素的 CSS 樣式?;蛘?,我們不移動(dòng)元素,拖動(dòng)的時(shí)候,復(fù)制一個(gè)副本,拖放結(jié)束后,我們就會(huì)多了一個(gè)同樣的元素。
本篇只介紹實(shí)現(xiàn)基本的拖放功能。
將元素設(shè)置成可拖動(dòng)的
我們先從拖動(dòng)元素開始。假設(shè)我們有一個(gè)容器元素,其中包含兩種類型的子元素:可拖動(dòng)元素和可放置元素。舉個(gè)例子,如果我們有一個(gè)待辦事項(xiàng)列表,我們可以將待辦事項(xiàng)拖到“完成”區(qū)域。
簡(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è)開始。拖拽過(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í)更新元素
下一步,我們開始設(shè)置 ondragstart 的事件處理器。
拖動(dòng)開始時(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)開始時(shí),如果修改了元素樣式,除非再次修改過(guò)來(lái),否則樣式是不會(huì)自動(dòng)恢復(fù)的。:rainbow:
拖動(dòng)開始時(shí)的處理函數(shù)寫好了,現(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è)要寫的處理函數(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)后還是看不見改變發(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)檫@是我們要寫的第三個(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>

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

只要依據(jù)本文上面已經(jīng)講過(guò)的內(nèi)容,稍微變通一下,就能寫出來(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中的JSON對(duì)象的定義和取值實(shí)現(xiàn)代碼
這篇文章主要介紹了JS中的JSON對(duì)象的定義和取值實(shí)現(xiàn)代碼,也是json的入門知識(shí),需要的朋友可以參考下2018-05-05
詳解如何使用微信小程序云函數(shù)發(fā)送短信驗(yàn)證碼
這篇文章主要介紹了詳解如何使用微信小程序云函數(shù)發(fā)送短信驗(yàn)證碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03
JS中函數(shù)科里化的背景與應(yīng)用實(shí)例教程
在數(shù)學(xué)和計(jì)算機(jī)科學(xué)中,柯里化是一種將使用多個(gè)參數(shù)的一個(gè)函數(shù)轉(zhuǎn)換成一系列使用一個(gè)參數(shù)的函數(shù)的技術(shù),下面這篇文章主要給大家介紹了JS中函數(shù)科里化的背景與應(yīng)用實(shí)例的相關(guān)資料,需要的朋友可以參考下2022-06-06
JS高級(jí)調(diào)試技巧:捕獲和分析 JavaScript Error詳解
前端工程師都知道 JavaScript 有基本的異常處理能力。我們可以 throw new Error(),瀏覽器也會(huì)在我們調(diào)用 API 出錯(cuò)時(shí)拋出異常。但估計(jì)絕大多數(shù)前端工程師都沒(méi)考慮過(guò)收集這些異常信息2014-03-03
原生JavaScript實(shí)現(xiàn)滾動(dòng)條效果
這篇文章主要介紹了原生JavaScript實(shí)現(xiàn)滾動(dòng)條效果的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-01-01
JavaScript中的this關(guān)鍵字使用方法總結(jié)
這篇文章主要介紹了JavaScript中的this關(guān)鍵字使用方法總結(jié),本文講解了作為對(duì)象方法調(diào)用、作為函數(shù)調(diào)用、作為構(gòu)造函數(shù)調(diào)用、使用 apply 或 call 調(diào)用等內(nèi)容,需要的朋友可以參考下2015-03-03
uni-app路由配置文件pages.json平臺(tái)化拆分
這篇文章主要為大家介紹了uni-app路由配置文件pages.json平臺(tái)化拆分示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01

