來學拖拉事件自己組漢堡包~~
拖拉事件 Drag Event 指的是使用者按住滑鼠不放,移動物體到另一個位置,再放開滑鼠將物體放置他處。
按住滑鼠的事件稱為 drag,放開滑鼠的事件稱為 drop。
draggable
設定才可以拖拉<div draggable='true'></div>
<div ondragover="event.preventDefault()">
drag
:拖拉過程會持續觸發dragstart
:拖拉時在被拖拉的節點上觸發,事件的 target 指向被拖拉的節點dragend
:拖拉結束時(鬆開滑鼠或按下 escape 鍵),在被拖拉的節點上觸發,事件的 target 是被拖拉的節點,與 dragstart
在同一個節點上觸發。dragenter
:拖拉進當前節點時,在當前節點上觸發,事件的 target 指向當前節點。dragover
:拖拉到當前節點時,在當前節點持續觸發,事件的 target 為當前節點。dragleave
:拖拉離開當前節點範圍時,在當前節點上觸發,事件 target 為當前節點drop
:被拖拉的節點釋放到目標節點時,在目標節點上觸發,但若是目標節點不允許 drop 行為,即時在目標節點上鬆開滑鼠,也不會觸發 drop 事件。由於大部分的網頁區域預設不允許 drop,若要使用 drop 須取消預設行為,使用語法 event.preventDefault()
。
設定方式是使用 dragenter
和 dragover
,當偵測到物體拖拉到範圍時,在監聽函數內加上 event.preventDefault()
就可以允許物體 drop 到目標範圍。
拖拉再 drop 有兩種情況:
先來看看第二種情況,要將目標物從 a 點複製到 b 點,從 createElement
改用 Node.cloneNode()
更方便!可以完全複製目標物的 css 設定,再用 appendChild
放置到 b 的節點下就完成拷貝行為囉~
node.cloneNode(deep); // deep 參數若為 true 表示連同子節點一起複製,false 則複製自己本身
做出來的畫面像這樣:
codepen drop 玩玩看
那麼如果是情況一:移動目標位置呢?
發揮想像力看看,是不是很適合來個大俠自組漢堡!
漢堡包實作連結
設計想法:使用者可以依照想要的食材,自己組裝漢堡。
<body>
<h1>BURGER</h1>
<div class="ingredient">
<img src='url' alt='漢堡上蓋' class="target" draggable="true">
<img src='url' alt='肉' class="target" draggable="true">
<img src='url' alt='肉' class="target" draggable="true">
<img src='url' alt='番茄' class="target" draggable="true">
<img src='url' alt='漢堡下蓋' class="target" draggable="true">
<img src='url' alt='青菜' class="target vagie" draggable="true">
<img src='url' alt='起司' class="target cheese" draggable="true">
</div>
<div class="assembly"></div>
</body>
JavaScript 實作:
在 document 下設定 dragstart
監聽事件,每次抓取的 event.target
會指向滑鼠拖拉的元素,將元素移動到桌布範圍時,使用 drop
將元素添加到桌布的節點下!
// 取節點
let get = (tag) => document.querySelector(tag);
let draggedTarget = null; // 宣告被抓取的目標物變數
// 設定抓取時的監聽事件
document.addEventListener("dragstart", function (event) {
console.log("抓到目標"); // test code
draggedTarget = event.target; // 將抓取時的目標物存入變數中
});
// 設定漢堡放置區的監聽事件
get(".assembly").addEventListener("drop", function (event) {
let previousIngredient = this.children[0]; // 取目前漢堡最上層材料
// 用 insertBefore ,將新抓取的材料疊在目前最上層的材料前,才可以製造漢堡往上堆疊的效果,否則用 appendChild 是變成往下疊唷!
this.insertBefore(draggedTarget, previousIngredient);
});
// 取消預設行為,才能使用 drop
document.addEventListener("dragover", function (event) {
event.preventDefault();
});
// 當沒有材料時拔掉材料區
document.body.addEventListener("drop", function (event) {
if (get(".ingredient").childElementCount === 0) {
let emptyBox = get(".ingredient");
this.removeChild(emptyBox);
}
});
隨著 Web API 知識增加可以玩得操作越來越多了~~~ 但碰到 css 都不小心太入迷,漢堡實作的 css 美化時間應該是寫邏輯的 2 倍以上 ...