Phá bỏ rào cản bằng cách sử dụng DataTransfer API

Cho phép người dùng chia sẻ dữ liệu ngoài cửa sổ trình duyệt.

Bạn có thể đã nghe nói về DataTransfer API. Đây là một phần của HTML5 Drag and Drop API (API Kéo và thả HTML5) và Sự kiện bảng nhớ tạm. Bạn có thể dùng đối tượng này để chuyển dữ liệu giữa mục tiêu nguồn và mục tiêu nhận.

Hỗ trợ trình duyệt

  • Chrome: 3.
  • Cạnh: 12.
  • Firefox: 3.5.
  • Safari: 4.

Nguồn

Các tương tác kéo-thả và sao chép-dán thường dùng cho các hoạt động tương tác trên một trang để chuyển văn bản đơn giản từ A sang B. Tuy nhiên, điều thường bị bỏ qua là khả năng sử dụng các hoạt động tương tác này để vượt ra ngoài cửa sổ trình duyệt.

Cả tính năng kéo và thả tích hợp sẵn của trình duyệt và các hoạt động tương tác sao chép và dán đều có thể giao tiếp với các ứng dụng khác, web hoặc ứng dụng khác và không liên kết với bất kỳ nguồn gốc nào. API này hỗ trợ nhiều mục nhập dữ liệu với các hành vi khác nhau dựa trên vị trí chuyển dữ liệu. Ứng dụng web của bạn có thể gửi và nhận dữ liệu đã chuyển khi nghe các sự kiện đến.

Khả năng này có thể thay đổi cách chúng ta nghĩ về việc chia sẻ và khả năng tương tác trong các ứng dụng web trên máy tính. Việc chuyển dữ liệu giữa các ứng dụng không cần dựa vào các tiện ích tích hợp được kết hợp chặt chẽ nữa. Thay vào đó, bạn có thể cấp cho người dùng toàn quyền kiểm soát để chuyển dữ liệu sang bất cứ nơi nào họ muốn.

Ví dụ về các hoạt động tương tác có thể thực hiện được với API DataTransfer. (Video không có âm thanh.)

Chuyển dữ liệu

Để bắt đầu, bạn cần triển khai thao tác kéo-thả hoặc sao chép-dán. Các ví dụ bên dưới cho thấy các hoạt động tương tác kéo và thả, nhưng quy trình sao chép và dán cũng tương tự như vậy. Nếu bạn chưa quen thuộc với API Kéo và thả, hãy tham khảo một bài viết tuyệt vời giải thích về tính năng Kéo và thả HTML5, bài viết này giải thích mọi thứ.

Bằng cách cung cấp dữ liệu khoá loại MIME, bạn có thể tự do tương tác với các ứng dụng bên ngoài. Hầu hết các trình chỉnh sửa WYSIWYG, trình chỉnh sửa văn bản và trình duyệt đều phản hồi các loại MIME "gốc" được sử dụng trong ví dụ bên dưới.

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');
});

Hãy lưu ý thuộc tính event.dataTransfer. Thao tác này sẽ trả về một thực thể của DataTransfer. Như bạn sẽ thấy, đối tượng này đôi khi được các thuộc tính có tên khác trả về.

Việc nhận dữ liệu chuyển gần giống với việc cung cấp dữ liệu chuyển. Theo dõi các sự kiện nhận (drop hoặc paste) và đọc các khoá. Khi kéo qua một phần tử, trình duyệt chỉ có quyền truy cập vào các khoá type của dữ liệu. Bạn chỉ có thể truy cập vào dữ liệu này sau khi thả.

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();
});

Ba loại MIME được hỗ trợ rộng rãi trên các ứng dụng:

  • text/html: Hiển thị tải trọng HTML trong các phần tử contentEditable và trình chỉnh sửa văn bản đa dạng thức (WYSIWYG) như Google Tài liệu, Microsoft Word và các trình chỉnh sửa khác.
  • text/plain: Đặt giá trị của các phần tử đầu vào, nội dung của trình soạn thảo mã và dự phòng từ text/html.
  • text/uri-list: Chuyển đến URL khi thả vào thanh URL hoặc trang trình duyệt. Lối tắt URL sẽ được tạo khi thả vào một thư mục hoặc máy tính.

Việc các trình soạn thảo WYSIWYG sử dụng rộng rãi text/html giúp trình soạn thảo này rất hữu ích. Giống như trong tài liệu HTML, bạn có thể nhúng tài nguyên bằng cách sử dụng URL dữ liệu hoặc URL có thể truy cập công khai. Cách này hoạt động tốt với việc xuất hình ảnh (ví dụ: từ canvas) sang các trình chỉnh sửa như Google Tài liệu.

const redPixel = 'data:image/gif;base64,R0lGODdhAQABAPAAAP8AAAAAACwAAAAAAQABAAACAkQBADs=';
const html = '<img src="' + redPixel + '" width="100" height="100" alt="" />';
event.dataTransfer.setData('text/html', html);

Chuyển bằng cách sao chép và dán

Dưới đây là cách sử dụng DataTransfer API với các hoạt động tương tác sao chép và dán. Xin lưu ý rằng đối tượng DataTransfer được thuộc tính có tên là clipboardData trả về cho các sự kiện trong bảng nhớ tạm.

// 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);
  }
});

Định dạng dữ liệu tuỳ chỉnh

Bạn không bị giới hạn ở các loại MIME gốc, nhưng có thể dùng bất kỳ khoá nào để xác định dữ liệu đã chuyển. Điều này có thể hữu ích cho các tương tác trên nhiều trình duyệt trong ứng dụng của bạn. Như minh hoạ bên dưới, bạn có thể chuyển dữ liệu phức tạp hơn bằng cách sử dụng các hàm 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);
  }
});

Kết nối web

Mặc dù định dạng tuỳ chỉnh rất phù hợp để giao tiếp giữa các ứng dụng mà bạn nắm quyền kiểm soát, nhưng định dạng này cũng hạn chế người dùng chuyển dữ liệu sang các ứng dụng không dùng định dạng của bạn. Nếu muốn kết nối với các ứng dụng của bên thứ ba trên web, bạn cần có một định dạng dữ liệu phổ quát.

Tiêu chuẩn JSON-LD (Dữ liệu được liên kết) là một lựa chọn tuyệt vời cho mục tiêu này. Tệp này nhẹ và dễ đọc và dễ ghi vào JavaScript. Schema.org chứa nhiều loại được xác định trước mà bạn có thể sử dụng, và định nghĩa giản đồ tuỳ chỉnh cũng là một lựa chọn.

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));

Khi sử dụng các loại Schema.org, bạn có thể bắt đầu với loại Thing chung hoặc sử dụng loại phù hợp hơn với trường hợp sử dụng của bạn như Event, Person, MediaObject, Place hoặc thậm chí các loại rất cụ thể như MedicalEntity nếu cần. Khi sử dụng TypeScript, bạn có thể sử dụng các định nghĩa giao diện từ định nghĩa loại schema-dts.

Bằng cách truyền và nhận dữ liệu JSON-LD, bạn sẽ hỗ trợ một web kết nối và cởi mở hơn. Khi các ứng dụng dùng cùng ngôn ngữ, bạn có thể tích hợp sâu với các ứng dụng bên ngoài. Không cần phải tích hợp API phức tạp; tất cả thông tin cần thiết đều có trong dữ liệu được chuyển.

Hãy nghĩ đến tất cả khả năng chuyển dữ liệu giữa mọi ứng dụng (web) mà không có giới hạn: chia sẻ sự kiện từ lịch đến ứng dụng ToDo yêu thích, đính kèm tệp ảo vào email, chia sẻ danh bạ. Điều đó thật tuyệt, phải không? Điều này bắt đầu từ bạn! 🙌

Mối quan tâm

Mặc dù DataTransfer API hiện đã có, nhưng bạn cần lưu ý một số điều trước khi tích hợp.

Khả năng tương thích với trình duyệt

Tất cả trình duyệt dành cho máy tính đều hỗ trợ rất tốt kỹ thuật được mô tả ở trên, trong khi thiết bị di động thì không. Kỹ thuật này đã được thử nghiệm trên tất cả các trình duyệt lớn (Chrome, Edge, Firefox, Safari) và các hệ điều hành (Android, ChromeOS, iOS, macOS, Ubuntu Linux và Windows), nhưng rất tiếc, Android và iOS không vượt qua được thử nghiệm này. Mặc dù các trình duyệt tiếp tục phát triển, nhưng hiện tại, kỹ thuật này chỉ giới hạn ở trình duyệt dành cho máy tính.

Tiềm năng khám phá

Thao tác kéo và thả cũng như sao chép và dán là các hoạt động tương tác ở cấp hệ thống khi làm việc trên máy tính để bàn, bắt nguồn từ các giao diện người dùng đồ hoạ đầu tiên cách đây hơn 40 năm. Hãy nghĩ về số lần bạn đã sử dụng các hoạt động tương tác này để sắp xếp các tệp. Điều này chưa phổ biến trên web.

Bạn cần hướng dẫn người dùng về cách tương tác mới này và đưa ra các mẫu trải nghiệm người dùng để họ có thể nhận ra, đặc biệt là những người chỉ có kinh nghiệm sử dụng máy tính trên thiết bị di động.

Hỗ trợ tiếp cận

Tính năng kéo và thả không phải là một cách tương tác dễ tiếp cận, nhưng API DataTransfer cũng hoạt động với tính năng sao chép và dán. Hãy nhớ theo dõi các sự kiện sao chép-dán. Bạn không cần làm gì thêm và người dùng sẽ biết ơn bạn vì đã thêm tính năng này.

Bảo mật và quyền riêng tư

Có một số điểm cần cân nhắc về bảo mật và quyền riêng tư mà bạn nên lưu ý khi sử dụng kỹ thuật này.

  • Các ứng dụng khác trên thiết bị của người dùng có thể sử dụng dữ liệu trên bảng nhớ tạm.
  • Các ứng dụng web bạn đang kéo qua có quyền truy cập vào các phím loại chứ không phải dữ liệu. Dữ liệu chỉ có sẵn khi thả hoặc dán.
  • Dữ liệu đã nhận phải được xử lý giống như mọi hoạt động đầu vào khác của người dùng; dọn dẹp và xác thực trước khi sử dụng.

Bắt đầu sử dụng thư viện trợ giúp Transmat

Bạn có hào hứng sử dụng API DataTransfer trong ứng dụng của mình không? Hãy cân nhắc việc xem thư viện Transmat trên GitHub. Thư viện nguồn mở này điều chỉnh những điểm khác biệt của trình duyệt, cung cấp các tiện ích JSON-LD, chứa một đối tượng tiếp nhận dữ liệu để phản hồi các sự kiện chuyển để đánh dấu vùng thả, đồng thời cho phép bạn tích hợp các hoạt động chuyển dữ liệu giữa các cách triển khai kéo và thả hiện có.

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);

Lời cảm ơn

Hình ảnh chính của Luba Ertel trên Unsplash.