HTML5的拖放(drag和drop)第一部分
拖放即抓取對象以后拖到另一個位置侣颂。HTML5中任何元素都能夠拖放档桃。
先來看一個簡單的示例了解拖放是什么?
可以看到用戶可使用鼠標(biāo)選擇可拖拽元素憔晒,將元素拖拽到可放置元素藻肄,并釋放鼠標(biāo)按鈕以放置這些元素。拖拽操作期間拒担,會有一個可拖拽元素的半透明快照跟隨著鼠標(biāo)指針嘹屯。
[圖片上傳失敗...(image-8d5426-1690085058496)]
核心代碼:
<div
id="dropBox"
ondrop="drop(event)"
ondragover="allowDrop(event)">
</div>
<br>
<div
id="dragBox"
draggable="true"
ondragstart="drag(event)">
可以把我拖到矩形框中
</div>
<script>
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("Text", ev.target.id);
}
function drop(ev) {
ev.preventDefault();
const data = ev.dataTransfer.getData("Text");
ev.target.appendChild(document.getElementById(data));
}
</script>
我們可以把拖放操作拆解為兩個部分:一個部分是針對可拖拽元素,另一個部分針對放置元素从撼。
可拖拽元素
draggable 屬性
draggable
屬性是一種枚舉類型屬性(不是布爾類型)州弟,用來標(biāo)識元素是否運行使用瀏覽器原生行為或HTML拖放操作。draggable
不能用于SVG
元素低零,只能用于嚴(yán)格屬于HTML
的元素婆翔。
draggable
的取值:
-
dragable="true"
:元素可以被拖動 -
dragable="false"
:元素不可用被拖動
如果不設(shè)置draggable
默認(rèn)為auto
。
在HTML中毁兆,除了圖像浙滤、鏈接和選中的文本有默認(rèn)的可拖拽行為以為,其他元素在默認(rèn)情況下是不可拖拽的气堕。**
要使其他的HTML元素可拖拽纺腊,必須:
- 將要拖拽到元素的
draggable
屬性設(shè)為true
; - 給可拖拽元素添加
dragstart
事件茎芭; - 在
dragstart
中設(shè)置拖拽數(shù)據(jù)揖膜。
dragstart 事件
當(dāng)用戶開始拖拽操作時,會觸發(fā)dragstart
事件梅桩。即在用戶開始拖動元素或被選擇的文本時調(diào)用壹粟。
dragstart
事件被添加到可拖拽元素本身。我們也可以監(jiān)聽它的祖先元素宿百,因為拖拽事件會冒泡趁仙。
dragstart
事件可以做什么操作?
在dragstart
事件中垦页,我們可以指定拖拽數(shù)據(jù)雀费、反饋圖像和拖拽效果。
拖拽數(shù)據(jù)
所有的拖拽事件中都有dataTransfer
屬性痊焊,它上面掛有拖拽數(shù)據(jù)盏袄。
要設(shè)置拖拽數(shù)據(jù)忿峻,使用setData()
方法,接收兩個參數(shù)辕羽,數(shù)據(jù)類型和數(shù)據(jù)值:
event.dataTransfer.setData("text/plain", "拖拽的內(nèi)容");
如果要提供多種格式的數(shù)據(jù)逛尚,可以用不同的數(shù)據(jù)類型多次調(diào)用setData()
方法。
const dt = event.dataTransfer;
dt.setData("application/x.bookmark", "bookmarkString");
dt.setData("text/uri-list", "http://www.mozilla.org");
dt.setData("text/plain", "http://www.mozilla.org");
如果需要以相同個數(shù)添加兩次數(shù)據(jù)刁愿,新數(shù)據(jù)會替換舊數(shù)據(jù)绰寞。使用clearData()
方法清除這些數(shù)據(jù),它接收一個參數(shù)铣口,要刪除的數(shù)據(jù)類型克握。
event.dataTransfer.clearData("text/uri-list");
clearData()
方法的參數(shù)type
是可選的。如果未聲明type
值枷踏,所有類型的數(shù)據(jù)都會被刪除菩暗。
反饋圖像
當(dāng)拖拽發(fā)生時,會生成拖拽元素的半透明圖像(觸發(fā)dragstart
事件的元素)旭蠕,并且在拖拽過程中跟蹤鼠標(biāo)指針停团。這個圖像是自動創(chuàng)建的,不需要手動創(chuàng)建它掏熬。但是我們可以使用setDragImage()
方法來自定義拖拽反饋圖像佑稠。
event.dataTransfer.setDragImage(image, xOffset, yOffset);
-
image
是圖像的引用,通常是一個<img>
元素旗芬,但是也可以是<canvas>
或任何其他元素舌胶,也可以使用不在文檔中的圖像和畫布。生成的反饋圖像就是該圖像在屏幕上的樣子疮丛,以圖像原始大小繪制幔嫂。 -
xOffset
,yOffset
是圖像位置相對于鼠標(biāo)指針位置的偏移量誊薄。
注意:使用
setDragImage()
修改反饋圖像履恩,image
元素必須存在于文檔中,如果不存在是不會生效的呢蔫,當(dāng)我們需要修改反饋圖像切心,實在沒辦法可以將反饋圖像在文檔中定位到視口以為的地方(但我不推薦)。我們可以用javascript
創(chuàng)建image
元素片吊。
示例1:修改拖動過程中的反饋圖像
效果1:將反饋圖像修改為<img>
[圖片上傳失敗...(image-c13a10-1690085058496)]
<div
id="dropBox"
ondrop="drop(event)"
ondragover="allowDrop(event)">
</div>
<br>
<div
id="dragBox"
draggable="true"
ondragstart="drag(event)">
可以把我拖到矩形框中
</div>
<script>
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
let img = new Image();
// img.src = "http://xxx.xx.drag.image"; // 方式1:外部圖片地址
img.src = "./drag.jpg"; // 方式2:本地圖片
ev.dataTransfer.setDragImage(img, 0, 0);
ev.dataTransfer.setData("Text", ev.target.id);
}
function drop(ev) {
ev.preventDefault();
const data = ev.dataTransfer.getData("Text");
ev.target.appendChild(document.getElementById(data));
}
</script>
效果2:將反饋圖像設(shè)置為canvas
[圖片上傳失敗...(image-134884-1690085058496)]
<div
id="dropBox"
ondrop="drop(event)"
ondragover="allowDrop(event)">
</div>
<br>
<div
id="dragBox"
draggable="true"
ondragstart="drag(event)">
可以把我拖到矩形框中
</div>
<canvas style="position: absolute; top: -2999px; left: -2999px"></canvas>
<script>
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
// 將反饋圖像設(shè)置為canvas
var canvas = document.querySelector("canvas");
canvas.width = 100;
canvas.height = 50;
let ctx = canvas.getContext("2d");
ctx.fillStyle = "green";
ctx.fillRect(10, 10, 200, 200);
ev.dataTransfer.setData("Text", ev.target.id);
ev.dataTransfer.setDragImage(canvas, 25, 25);
}
function drop(ev) {
ev.preventDefault();
const data = ev.dataTransfer.getData("Text");
ev.target.appendChild(document.getElementById(data));
}
</script>
拖拽效果
拖拽過程中可能會執(zhí)行一些操作绽昏,給指定屬性設(shè)置不同的值,會影響到拖拽過程中瀏覽器顯示的鼠標(biāo)樣式
在dragstart
事件中可以設(shè)置effectAllowed
屬性以指定允許拖拽源頭執(zhí)行三種操作中的哪幾種俏脊。默認(rèn)情況我們不需要修改該屬性全谤,除非特殊情況。
// 在dragstart事件中設(shè)置`effectAllowed`為`none`联予,表示不允許拖放操作
event.dataTransfer.effectAllowed = "none";
// 取值有
effectAllowed: none | copy | move | link | copyMove | copyLink | linkMove | all
在拖拽操作期間啼县,dragenter
或dragover
事件的監(jiān)聽程序可以檢查effectAllowed
屬性,以判定允許執(zhí)行哪些操作沸久。在dragenter
或dragover
事件中我們可以設(shè)置dropEffect
屬性季眷,來指定應(yīng)該執(zhí)行哪一個單項操作。
// 在`dragenter`或`dragover`事件中設(shè)置`dropEffect`為`none`
event.dataTransfer.dropEffect = "move";
dropEffect
屬性用來控制拖放操作中用戶給予的反饋卷胯,會影響拖拽過程中瀏覽器顯示的鼠標(biāo)樣式子刮。
// 取值有
dropEffect: none | copy | link | move
drag 事件
drag
事件中用戶拖動元素或選擇文本時,每隔幾百ms觸發(fā)一次窑睁。
// 可以使用`addEventListener()`方法或者`ondrag`
addEventListener('drag', (event) => {});
ondrag = (event) => { };
dragend 事件
dragend
:當(dāng)拖拽操作結(jié)束時觸發(fā)(比如松開鼠標(biāo)按鍵或ESC
按鍵)挺峡。
dragend
事件無法被取消。
當(dāng)拖拽操作結(jié)束時担钮,在開始拖拽的目標(biāo)元素(可拖拽元素)上觸發(fā)dragend
事件橱赠。不管拖拽是完成還是取消都會被觸發(fā)。dragend
事件可以檢查dropEffect
屬性的值來確認(rèn)拖拽是否成功箫津。
function dragend(ev) {
console.log(ev.dataTransfer.dropEffect) // 如果值為none表示拖拽被取消
}
放置元素
內(nèi)容太多狭姨,就分兩個部分吧,下一部分介紹放置元素的相關(guān)內(nèi)容苏遥。
單擊此處查看HTML5拖放API第二部分