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 bên ngoài cửa sổ trình duyệt.

Bạn có thể đã nghe về API Chuyển dữ liệu, một phần của API Kéo và thả HTML5Sự kiện bảng điều khiển. Bạn có thể dùng đối tượng này để chuyển dữ liệu giữa đích nguồn và đích nhận.

Hỗ trợ trình duyệt

  • 3
  • 12
  • 3,5
  • 4

Nguồn

Các hoạt động tương tác kéo-thả và sao chép-dán thường được dùng cho các hoạt động tương tác trong một trang để chuyển văn bản đơn giản từ A sang B. Nhưng điều thường bị bỏ qua là khả năng sử dụng những tương tác tương tự 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 lẫn các hoạt động tương tác sao chép và dán của trình duyệt đều có thể giao tiếp với các ứng dụng khác, web hoặc các ứng dụng khác và không gắn liền với bất kỳ nguồn gốc nào. API này hỗ trợ nhiều mục dữ liệu với nhiều hành vi tuỳ theo nơi dữ liệu được chuyển đến. Ứng dụng web của bạn có thể gửi và nhận dữ liệu đã chuyển khi theo dõi các sự kiện đến.

Tính năng này có thể thay đổi cách suy nghĩ của chúng ta 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 phải dựa vào các công cụ tích hợp được ghép nối 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 đến bất kỳ 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 bằng API DataTransfer. (Video không có âm thanh.)

Đang 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 và 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 hiểu rõ về API Kéo và thả, bạn có thể 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, trong đó giải thích tất cả các đặc điểm.

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

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 khi, đối tượng này được các thuộc tính có tên khác trả về.

Việc nhận dữ liệu được chuyển hoạt động gần giống như quá trình cung cấp dữ liệu đó. 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. Chỉ có thể truy cập vào dữ liệu này sau khi dữ liệu bị sụt giảm.

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

3 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à bản dự phòng từ text/html.
  • text/uri-list: Di 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àn hình.

Việc sử dụng rộng rãi text/html của các trình chỉnh sửa WYSIWYG khiến tính năng này trở nên rất hữu ích. 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 hiệu quả khi 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 thao tác sao chép và dán

Cách sử dụng DataTransfer API với các hoạt động tương tác sao chép và dán được hiển thị bên dưới. Xin lưu ý rằng đối tượng DataTransfer được một 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ể sử dụng bất kỳ khoá nào để xác định dữ liệu được 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ư hình minh hoạ dưới đây, 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 là lựa chọn tuyệt vời để giao tiếp giữa các ứng dụng mà bạn có quyền kiểm soát, nhưng định dạng này cũng giới hạn người dùng khi chuyển dữ liệu đến các ứng dụng không sử dụng định dạng của bạn. Nếu muốn kết nối với các ứng dụng bên thứ ba trên web, bạn cần có một định dạng dữ liệu chung.

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

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 bằng loại Thing chung hoặc sử dụng loại nào đó gần với trường hợp sử dụng của bạn hơn như Event, Person, MediaObject, Place hoặc thậm chí là 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 môi trường web mở và kết nối hơn. Với các ứng dụng dùng cùng một ngôn ngữ, bạn có thể tích hợp sâu với các ứng dụng bên ngoài. Bạn 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 đưa vào dữ liệu được chuyển.

Hãy nghĩ đến tất cả các khả năng truyền dữ liệu giữa mọi ứng dụng (web) mà không có hạn chế: chia sẻ sự kiện từ lịch sang ứng dụng Công việc yêu thích của bạn, đí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ù hiện đã có API DataTransfer, 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ả các trình duyệt dành cho máy tính đều hỗ trợ tuyệt vời cho kỹ thuật này, còn 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 chính (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 là Android và iOS không vượt qua được bài kiểm thử. Trong khi các trình duyệt vẫn tiếp tục phát triển, hiện tại, kỹ thuật này chỉ giới hạn cho các trình duyệt dành cho máy tính.

Tiềm năng được khám phá

Kéo và 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 GUI đầ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 tệp. Điều này chưa phải là quá phổ biến trên web.

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

Hỗ trợ tiếp cận

Kéo và thả không phải là một tương tác dễ truy cập, 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 và dán. Bạn không cần làm gì thêm và người dùng của bạn sẽ rất biết ơn vì bạn đã thêm tính năng này.

Mức độ bảo mật và quyền riêng tư

Có một số lưu ý về bảo mật và quyền riêng tư bạn nên biết khi sử dụng kỹ thuật này.

  • Dữ liệu bảng nhớ tạm có sẵn cho các ứng dụng khác trên thiết bị của người dùng.
  • 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, 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; hãy 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ình trợ giúp Transmat

Bạn có muốn sử dụng DataTransfer API 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 trình quan sát để phản hồi các sự kiện chuyển nhằm làm nổi bật các vùng thả, đồng thời cho phép bạn tích hợp các thao tác chuyển dữ liệu giữa các phương thức 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);

Xác nhận

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