讓使用者在瀏覽器視窗外分享資料。
您可能聽過 DataTransfer API,這是 HTML5 Drag and Drop API 和 剪貼簿事件 的一部分。可用於在來源和接收目標之間轉移資料。
拖曳與複製貼上互動通常用於網頁內的互動,將簡單的文字從 A 轉移到 B。但我們經常忽略的是,這些互動功能的用途不只限於瀏覽器視窗。
瀏覽器內建的拖曳和複製貼上互動功能可以與其他應用程式、網路或其他位置通訊,而且與任何來源並無關聯。此 API 支援根據資料傳輸位置,具有不同行為的多個資料項目。您的網頁應用程式可在監聽傳入事件時,傳送及接收已轉移的資料。
這項功能可以改變我們對電腦版網頁應用程式的分享和互通性觀念。在應用程式之間轉移資料時,不必再仰賴緊密整合。您可以改為讓使用者擁有完整控制權 將資料移轉至任意位置
轉移資料
如要開始使用,您必須實作拖曳或複製貼上功能。下方為拖曳互動範例,但複製貼上的程序很類似。如果您不熟悉拖曳放置 API,請參閱這篇說明 HTML5 拖曳放置功能的優質文章,瞭解相關細節。
提供 MIME 類型鍵資料後,即可自由與外部應用程式互動。大部分的 WYSIWYG 編輯器、文字編輯器和瀏覽器都回應以下範例中使用的「原始」MIME 類型。
document.querySelector('#dragSource')
.addEventListener('dragstart', (event) => {
event.dataTransfer.setData('text/plain', 'Foo bar');
event.dataTransfer.setData('text/html', '<h1>Foo bar</h1>');
event.dataTransfer.setData('text/uri-list', 'https://example.com');
});
請注意 event.dataTransfer
屬性。這會傳回 DataTransfer
的執行個體。如您所見,這個物件有時會由具有其他名稱的屬性傳回。
接收資料移轉作業的方式與提供資料幾乎相同。監聽接收事件 (drop
或 paste
) 並讀取鍵。拖曳元素時,瀏覽器只能存取資料的 type
鍵。只有在掉落後才能存取資料本身。
document.querySelector('#dropTarget')
.addEventListener('dragover', (event) => {
console.log(event.dataTransfer.types);
// Without this, the drop event won't fire.
event.preventDefault();
});
document.querySelector('#dropTarget')
.addEventListener('drop', (event) => {
// Log all the transferred data items to the console.
for (let type of event.dataTransfer.types) {
console.log({ type, data: event.dataTransfer.getData(type) });
}
event.preventDefault();
});
應用程式普遍支援三種 MIME 類型:
text/html
:在contentEditable
元素和 Google 文件、Microsoft Word 等富文字 (WYSIWYG) 編輯器中轉譯 HTML 酬載。text/plain:
設定輸入元素、程式碼編輯器的內容和text/html
的備用值。text/uri-list
:在網址列或瀏覽器頁面上放置時,會前往該網址。將檔案拖曳至目錄或桌面時,系統會建立網址捷徑。
所見即所得,所見即所得,WYSIWYG 編輯器廣泛採用 text/html
時非常實用。就像在 HTML 文件中一樣,您可以使用資料網址或公開存取網址來嵌入資源。這項功能適用於將圖像 (例如從畫布) 匯出至 Google 文件等編輯器。
const redPixel = 'data:image/gif;base64,R0lGODdhAQABAPAAAP8AAAAAACwAAAAAAQABAAACAkQBADs=';
const html = '<img src="' + redPixel + '" width="100" height="100" alt="" />';
event.dataTransfer.setData('text/html', html);
使用複製及貼上功能轉移
以下是使用 DataTransfer API 與複製貼上互動方式的範例。請注意,剪貼簿事件的 DataTransfer
物件是由名為 clipboardData
的屬性傳回。
// Listen to copy-paste events on the document.
document.addEventListener('copy', (event) => {
const copySource = document.querySelector('#copySource');
// Only copy when the `activeElement` (i.e., focused element) is,
// or is within, the `copySource` element.
if (copySource.contains(document.activeElement)) {
event.clipboardData.setData('text/plain', 'Foo bar');
event.preventDefault();
}
});
document.addEventListener('paste', (event) => {
const pasteTarget = document.querySelector('#pasteTarget');
if (pasteTarget.contains(document.activeElement)) {
const data = event.clipboardData.getData('text/plain');
console.log(data);
}
});
自訂資料格式
不限於原始 MIME 類型,但可以使用任何金鑰識別已轉移的資料。這對於應用程式中的跨瀏覽器互動相當實用。如以下所示,您可以使用 JSON.stringify()
和 JSON.parse()
函式傳輸更複雜的資料。
document.querySelector('#dragSource')
.addEventListener('dragstart', (event) => {
const data = { foo: 'bar' };
event.dataTransfer.setData('my-custom-type', JSON.stringify(data));
});
document.querySelector('#dropTarget')
.addEventListener('dragover', (event) => {
// Only allow dropping when our custom data is available.
if (event.dataTransfer.types.includes('my-custom-type')) {
event.preventDefault();
}
});
document.querySelector('#dropTarget')
.addEventListener('drop', (event) => {
if (event.dataTransfer.types.includes('my-custom-type')) {
event.preventDefault();
const dataString = event.dataTransfer.getData('my-custom-type');
const data = JSON.parse(dataString);
console.log(data);
}
});
連線至網路
雖然自訂格式適合由您控管的應用程式之間進行通訊,但也會限制使用者在將資料轉移至未使用您格式的應用程式時。如果想與網路上的第三方應用程式連結,就需要通用資料格式。
JSON-LD (連結資料) 標準非常適合用於這項作業。這項工具體積輕巧,且在 JavaScript 中容易讀取及寫入。Schema.org 包含許多可用的預先定義類型,也可選擇自訂結構定義。
const data = {
'@context': 'https://schema.org',
'@type': 'ImageObject',
contentLocation: 'Venice, Italy',
contentUrl: 'venice.jpg',
datePublished: '2010-08-08',
description: 'I took this picture during our honey moon.',
name: 'Canal in Venice',
};
event.dataTransfer.setData('application/ld+json', JSON.stringify(data));
使用 Schema.org 類型時,您可以從一般 Thing 類型開始,或是使用更符合用途的類型,例如 Event、Person、MediaObject、Place,甚至是 MedicalEntity 等非常特定的類型。使用 TypeScript 時,您可以使用 schema-dts 類型定義中的介面定義。
透過傳輸及接收 JSON-LD 資料,您可以支援更具連結且開放的網路環境。如果您使用的應用程式使用相同的語言,您就可以與外部應用程式建立深度整合。您不需要使用複雜的 API 整合,需要的所有資訊都會包含在轉移的資料中。
您不妨思考在無限制的情況下,在任何 (網頁應用程式) 之間轉移資料的方法,例如將行事曆中的活動分享到您喜愛的「待辦事項」應用程式、將虛擬檔案附加到電子郵件,以及共用聯絡人。這樣應該很棒,對吧?一切都從你開始!🙌
疑慮
雖然 DataTransfer API 現已推出,但在整合前,請先留意以下事項。
瀏覽器相容性
電腦版瀏覽器都提供上述技術的完整支援,但行動裝置則無法。在所有主要瀏覽器 (Chrome、Edge、Firefox、Safari) 和作業系統 (Android、ChromeOS、iOS、macOS、Ubuntu Linux 和 Windows) 上,這項技術都已經過測試,但 Android 和 iOS 並未通過測試。雖然瀏覽器仍在持續開發,但目前這項做法僅適用於電腦版瀏覽器。
爭取曝光機會
在電腦上工作時,拖曳和複製貼上是系統層級互動,其歷史可追溯至 40 多年前的首個 GUI。請想想您使用這些互動整理檔案的次數。網路上還有少許這種全新的內容。
您必須向使用者說明這項新的互動,並構思使用者體驗模式,使其更容易辨識。尤其對於目前習慣不仰賴行動裝置的使用者來說,更是如此。
無障礙設定
拖曳方法並不容易存取,但 DataTransfer API 也可以支援複製貼上。請務必監聽複製貼上事件。這項操作不需要您多費工夫,而且系統會很感謝新增這個 API 的使用者。
安全性和隱私權
使用這項技術時,請注意一些安全性和隱私權考量事項。
- 使用者裝置上的其他應用程式可存取剪貼簿資料。
- 您拖曳的網頁應用程式可以存取類型鍵,而非資料。資料只有在捨棄或貼上時才可供使用。
- 收到的資料應視為其他使用者輸入,請清除並驗證資料,再使用。
開始使用 Transmat 輔助程式庫
您有興趣在應用程式中使用 DataTransfer API 嗎?建議您查看 GitHub 上的 Transmat 程式庫。這個開放原始碼程式庫可調整瀏覽器差異、提供 JSON-LD 公用程式,並包含觀察器,可回應轉移事件,以便醒目顯示放置區域,並讓您在現有的拖曳和放置實作中整合資料轉移作業。
import { Transmat, TransmatObserver, addListeners } from 'transmat';
// Send data on drag/copy.
addListeners(myElement, 'transmit', (event) => {
const transmat = new Transmat(event);
transmat.setData({
'text/plain': 'Foobar',
'application/json': { foo: 'bar' },
});
});
// Receive data on drop/paste.
addListeners(myElement, 'receive', (event) => {
const transmat = new Transmat(event);
if (transmat.hasType('application/json') && transmat.accept()) {
const data = JSON.parse(transmat.getData('application/json'));
}
});
// Observe transfer events and highlight drop areas.
const obs = new TransmatObserver((entries) => {
for (const entry of entries) {
const transmat = new Transmat(entry.event);
if (transmat.hasMimeType('application/json')) {
entry.target.classList.toggle('drag-over', entry.isTarget);
entry.target.classList.toggle('drag-active', entry.isActive);
}
}
});
obs.observe(myElement);
特別銘謝
主頁橫幅由 Luba Ertel 在 Unsplash 提供。