iT邦幫忙

2025 iThome 鐵人賽

DAY 9
1
Modern Web

從 Canvas 到各式各樣的 Web API 之旅系列 第 9

Day 9 - 用 Drag and Drop API 拖曳 DOM 元素

  • 分享至 

  • xImage
  •  

結束了精彩的 Canvas API 系列,接下來要帶大家探索更多有趣又實用的 Web API!🎉

首先登場的是 HTML5 的 Drag and Drop API 拖曳功能

在前幾天的 Canvas 範例裡,我們其實也有透過滑鼠事件手動實作過「拖曳」效果。那種做法比較接近「遊戲式」的互動,需要完全掌控座標與繪製過程。

而今天要介紹的 Drag and Drop API,則是瀏覽器專為 DOM 元素 提供的原生機制,用起來更直覺,特別適合應用在檔案上傳、拖曳排序、或各種 UI 元素的互動操作。

過去多半用手動監聽滑鼠事件來實現拖曳,雖然彈性高,但也容易踩到各種坑。現在有了原生的 Drag and Drop API,可以讓這些互動變得更簡單、標準化。


基本概念

Drag and Drop API 的核心觀念是:把元素設為可拖曳,並透過一系列事件完成「拖 → 放」的流程

1. draggable 屬性

只要在元素上加上 draggable="true",它就能成為可拖曳的物件。

<div draggable="true">拖曳我</div>

2. 拖曳事件流程

在網頁中,拖曳操作主要分為兩部分:被拖曳元素與放置目標,各自會觸發不同事件。

被拖曳元素(draggable)的事件

  • dragstart:拖曳開始時觸發,可設定要傳遞的資料。
  • drag:拖曳過程中持續觸發。
  • dragend:拖曳結束時觸發(不論是否成功放在放置目標)。

dragstart

dragend

放置目標(dropzone)的事件

  • dragenter:拖曳物件進入目標區域時觸發。
  • dragover:拖曳物件停留在目標上時持續觸發,要在這裡 event.preventDefault() 才能允許放置。
  • dragleave:拖曳物件離開目標區域時觸發。
  • drop:物件放下時觸發,可在這裡取出資料。

dragenter

dragleave

drop

事件流程示意圖

被拖曳元素:
[dragstart] → [drag] → [dragend]

放置目標:
[dragenter] → [dragover] → [drop]
              ↘ [dragleave]

3. dataTransfer 物件

event.dataTransfer 是拖曳過程的關鍵,用來傳遞資料。

  • setData(type, data):在 dragstart 設定要傳遞的資料。
  • getData(type):在 drop 取回資料。
  • 也能處理檔案,透過 dataTransfer.files 讀取使用者拖曳進來的檔案。

附上簡易的程式碼

理解了基本概念後,我們來看一個最簡單的範例:把一個方塊拖曳到指定區域。

HTML

<div class="drag-source" draggable="true">拖曳我</div>
<div class="drop-target">放到這裡</div>

CSS

.drag-source {
  width: 100px;
  height: 100px;
  background: #5aa9e6;
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: grab;
}

.drop-target {
  width: 200px;
  height: 200px;
  border: 2px dashed #aaa;
  margin-top: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #555;
}

JavaScript

const dragSource = document.querySelector(".drag-source");
const dropTarget = document.querySelector(".drop-target");

// 拖曳開始時,設定傳遞的資料
dragSource.addEventListener("dragstart", (e) => {
  e.dataTransfer.setData("text/plain", "Hello Drag and Drop!");
});

// 允許放置
// 注意:沒有 preventDefault(),drop 事件不會觸發
dropTarget.addEventListener("dragover", (e) => {
  e.preventDefault();
});

// 放下物件時,取出資料
dropTarget.addEventListener("drop", (e) => {
  e.preventDefault();
  const data = e.dataTransfer.getData("text/plain");
  dropTarget.textContent = `接收到資料:${data}`;
});

效果

  • 拖曳上方的方塊到目標區域。
  • dragstart 事件會把資料放進 dataTransfer
  • 當元素被放下時,drop 事件讀取資料並更新目標區塊內容。

延伸閱讀

雖然我們最常在 drop 事件裡讀取資料,但其實在 同一頁元素的拖曳 裡,你也能在 dragenterdragover 時就呼叫 getData("text/plain"),提前拿到 dragstart 設定的值,用來做即時提示。

不過若是 跨應用拖曳(例如把桌面檔案拖進網頁),在 dragenter / dragover 階段通常只會提供檔案的「metadata」(例如檔名、型別),而真正的檔案內容則必須等到 drop 事件才會暴露。

這是瀏覽器刻意的安全設計,避免惡意網站只要你「拖曳經過」頁面,就偷取電腦裡檔案的內容。


範例 Demo

上面我們用簡單程式碼展示了最基本的拖曳流程。
如果想直接體驗完整的互動效果,可以參考這個線上範例(同時也是本文截圖的來源):


👉 歡迎追蹤這個系列,我會從 Canvas 開始,一步步帶你認識更多 Web API 🎯


上一篇
Day 8 - Canvas 跨域安全:理解並避免 Tainted Canvas 問題
系列文
從 Canvas 到各式各樣的 Web API 之旅9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言