拖放事件
拖放操作是將一個元素拖放到另一個元素的操作擦剑,這項操作涉及到兩個元素:被拖放元素和放置元素澜倦。在拖放過程中仇参,被拖放元素會經(jīng)歷以下幾個事件:
dragstart
drag
dragend
當我們將被拖放元素拖動到放置元素(目標元素)時咧纠,會經(jīng)歷以下幾個事件:
dragenter
dragover
-
drop
或dragleave
其中,drop
事件在被拖放元素放置到目標元素上時觸發(fā)秽澳,dropleave
事件在被拖放元素離開目標時觸發(fā)闯睹。
觸發(fā) drop 事件
默認情況下,某些元素是不允許放置目標的(如 div
)担神,在這些元素上楼吃,無法觸發(fā) drop
事件,但是能觸發(fā)dragenter
、dragover
和dragleave
三個事件孩锡】嵯看個例子:
...
<style>
img{
width: 100px;
height: 100px;
border:10px solid orange;
}
#box{
width: 200px;
height: 200px;
background-color:bisque;
margin:50px auto;
}
</style>
...
<body>
![](./01.png)
<div id="box"></div>
</body>
...
<script>
img.addEventListener("dragstart",(e)=>{
console.log("拖動開始")
})
box.addEventListener("dragenter",(e)=>{
console.log("觸發(fā) dragenter 事件")
})
box.addEventListener("dragover",(e)=>{
console.log("觸發(fā) dragover 事件")
})
box.addEventListener("drop",(e)=>{
console.log("觸發(fā) drop 事件")
})
box.addEventListener("dragleave",(e)=>{
console.log("觸發(fā) dragleave 事件")
})
</script>
...
運行效果:
可見,默認情況下是無法觸發(fā)
drop
事件的浮创,并且將拖放元素放到目標元素上時還會觸發(fā)目標元素的 dragleave
事件忧吟。如果我們想觸發(fā)目標元素的
drop
事件,需要阻止目標元素的 dragenter
和 dragover
事件的默認行為斩披。
...
box.addEventListener("dragenter",(e)=>{
console.log("觸發(fā) dragenter 事件")
e.preventDefault();
})
box.addEventListener("dragover",(e)=>{
console.log("觸發(fā) dragover 事件")
e.preventDefault();
})
...
運行效果如下:
可見,阻止目標元素
dragenter
和 dragover
事件的默認行為后讹俊,可以正常觸發(fā) drop
事件了垦沉,同時,當把拖放元素放到目標元素上時仍劈,不會再觸發(fā)dragleave
事件了厕倍。
消息傳遞
在拖放操作時,可能需要進行數(shù)據(jù)的傳遞贩疙,典型的如拖放的購物車功能讹弯,需要將商品信息傳遞到購物車列表中,這就需要消息傳遞了这溅。
拖拽事件的事件對象中有一個 dataTransfer
屬性组民,可以利用該屬性來傳遞和接受消息:
-
dataTransfer.setData(key,value)
:用來防止消息 -
dataTransfer.getData(key)
:用來獲取消息
需要注意的是,dataTransfer.getData
這個方法悲靴,只有在 drop
事件中才能獲取到數(shù)據(jù)臭胜,在其他事件中是獲取不到數(shù)據(jù)的。
將上面的例子簡單修改一下:
let flag = 1;
let goodsList = [];
img.addEventListener("dragstart",(e)=>{
e.dataTransfer.setData("item",`商品${flag++}`)
})
box.addEventListener("dragenter",(e)=>{
e.preventDefault();
})
box.addEventListener("dragover",(e)=>{
e.preventDefault();
})
box.addEventListener("drop",(e)=>{
const goodsInfo = e.dataTransfer.getData("item");
goodsList.push(goodsInfo)
console.log(`已有${goodsList.length}件商品了`)
box.innerHTML = goodsList.length;
})
運行效果:
控制光標樣式
dataTransfer
這個屬性除了可以用來傳遞消息之外癞尚,還可以規(guī)定被拖動元素和目標元素的行為耸三,其中,被拖動元素的行為由 dataTransfer
的 effectAllowed
屬性控制浇揩,目標元素的行為由 dataTransfer
的 dropEffect
屬性控制仪壮。
其中,effectAllowed
屬性必須在拖放元素的 dragstart
事件中設(shè)置胳徽,dropEffect
屬性必須在目標元素的 dragenter
事件中設(shè)置积锅。
另外,effectAllowed
需要和 dragEffect
搭配使用膜廊。
其中乏沸,effectAllowed
屬性可以設(shè)置以下幾個值:
"none":不能把拖動的元素放在這里。這是除文本框之外所有元素的默認值爪瓜。
"move":應(yīng)該把拖動的元素移動到放置目標蹬跃。
"copy":應(yīng)該把拖動的元素復(fù)制到放置目標。
"link":表示放置目標會打開拖動的元素(但拖動的元素必須是一個鏈接,有 URL)蝶缀。
dropEffect
屬性可以設(shè)置以下幾個值:
"uninitialized":沒有給被拖動的元素設(shè)置任何放置行為丹喻。
"none":被拖動的元素不能有任何行為。
"copy":只允許值為"copy"的 dropEffect翁都。
"link":只允許值為"link"的 dropEffect碍论。
"move":只允許值為"move"的 dropEffect。
"copyLink":允許值為"copy"和"link"的 dropEffect柄慰。
"copyMove":允許值為"copy"和"move"的 dropEffect鳍悠。
"linkMove":允許值為"link"和"move"的 dropEffect。
"all":允許任意 dropEffect坐搔。
以上引用自 《JavaScript 高級程序設(shè)計(第三版)》藏研。
需要注意的是:設(shè)置 effectAllowed
和 dropEffect
屬性只能改變光標的樣式,但不會對真實的 DOM 節(jié)點進行復(fù)制或移動等操作概行。如果你需要對真實的 DOM 進行移動或復(fù)制操作蠢挡,還需要自己去實現(xiàn)。
setDragImage 方法
該方法也是 dataTransfer
屬性上的一個方法凳忙,用來設(shè)置拖放元素時顯示在光標下的圖像业踏,該方法的使用方式如下:
dataTransfer.setDragImage(element,xpos,ypos);
其中 element
參數(shù)是顯示在鼠標下的元素,xpos
和 ypos
分別是鼠標相對于元素的坐標涧卵。
將前面的例子做一些修改勤家,看下運行效果:
...
<style>
img{
width: 100px;
height: 100px;
border:10px solid orange;
}
#box{
width: 200px;
height: 200px;
background-color:bisque;
margin:50px auto;
}
#dragImg{
width: 100px;
height: 100px;
background:red;
border-radius: 50%;
opacity: 0;
}
</style>
...
<body>
![](./01.png)
<div id="box"></div>
<div id="dragImg"></div>
</body>
...
<script>
img.addEventListener("dragstart",(e)=>{
if(Math.random() > 0.5){
e.dataTransfer.setDragImage(dragImg,0,0);
dragImg.style.opacity = 1;
}else{
e.dataTransfer.setDragImage(img,0,0);
}
})
box.addEventListener("dragenter",(e)=>{
e.preventDefault();
})
box.addEventListener("dragover",(e)=>{
e.preventDefault();
})
</script>
...
運行效果:
上面的代碼使用兩個元素進行了對比,在實際用途中艺演,這個方法還是很有用的却紧,可以用來設(shè)置拖放時鼠標指針下的背景圖像(元素)以及位置,方便我們進行定制胎撤。
使任意元素可拖動
默認情況下晓殊,只有圖片、鏈接和文本是可以拖動的伤提,要想使其他的元素可拖動巫俺,只需設(shè)置元素的 draggable
屬性為 true
即可。
總結(jié)
本文主要介紹了 HTML5 中的拖放事件肿男,包括:
- 被拖放元素和目標元素的幾個對應(yīng)事件
- 如何阻止默認行為從而可以觸發(fā)
drop
事件 - 如何使用
dataTransfer
傳遞消息 - 如何使用
effectAllowed
和dropEffect
控制光標樣式 - 如何使用
setDragImage()
方法設(shè)置拖放時的背景圖像 - 如何使任意元素可拖動
關(guān)于拖放事件介汹,還剩下一點內(nèi)容,主要是文件相關(guān)的操作(拖放上傳文件)舶沛。鑒于篇幅嘹承,將拖放事件拆成兩篇,下篇內(nèi)容主要寫和文件相關(guān)的一些操作如庭。