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 phương thức này để chuyển dữ liệu giữa nguồn và đích nhận.

Hỗ trợ trình duyệt

  • Chrome: 3.
  • Edge: 12.
  • Firefox: 3.5.
  • Safari: 4.

Nguồn

Các thao tác tương tác kéo và thả cũng như sao chép và dán thường được dùng để tương tác trong 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 hoạt động 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 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 tính năng kéo và 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ự. Nếu bạn chưa quen với API Kéo và thả, hãy tham khảo bài viết tuyệt vời giải thích về tính năng Kéo và thả trong HTML5 để tìm hiểu toàn bộ thông tin.

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

Có 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à 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 chỉnh sửa WYSIWYG sử dụng rộng rãi text/html khiến lớp 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 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. Lưu ý rằng đối tượng DataTransfer được trả về bởi một thuộc tính có tên là clipboardData cho các sự kiện 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 nguyên thuỷ mà 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 hoạt động 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 có quyền kiểm soát, nhưng định dạng này cũng hạn chế người dùng khi chuyển dữ liệu sang 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 phổ quát.

Tiêu chuẩn JSON-LD (Dữ liệu liên kết) là một lựa chọn phù hợp cho việc này. Lớp này có kích thước nhỏ và dễ đọc cũng như ghi vào trong JavaScript. Schema.org chứa nhiều loại được xác định trước mà bạn có thể sử dụng, đồng thời bạn cũng có thể sử dụng đị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 chung hoặc sử dụng một loại 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 web kết nối và cởi mở hơn. Với các ứng dụng sử dụng cùng một ngôn ngữ, bạn có thể tạo các chế độ 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ó trong dữ liệu được chuyển.

Hãy nghĩ đến tất cả cá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ạ. Thật tuyệt vời phải không? Mọi thứ bắt đầu từ bạn! 🙌

Mối quan tâm

Mặc dù API DataTransfer 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 chính (Chrome, Edge, Firefox, Safari) và hệ điều hành (Android, ChromeOS, iOS, macOS, Ubuntu Linux và Windows), nhưng đáng tiếc là Android và iOS không vượt qua được bài kiểm thử. 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á

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 thao tác tương tác này để sắp xếp tệp. Điều này chưa phổ biến trên web.

Bạn sẽ 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 để người dùng 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. Việc này không mất nhiều công sức và người dùng sẽ cảm ơn bạn vì đã thêm tính năng này.

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

Bạn cần lưu ý một số vấn đề về bảo mật và quyền riêng tư 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 mà bạn đang kéo có quyền truy cập vào các khoá 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 được phải được xử lý như mọi dữ liệu đầ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ợ giúp Transmat

Bạn có hào hứng sử dụng DataTransfer API trong ứng dụng của mình không? Hãy cân nhắc xem thư viện Transmat trên GitHub. Thư viện nguồn mở này điều chỉnh các đ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 trình quan sát để phản hồi các sự kiện chuyển để làm nổi bật các khu vực thả và 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);

Lời cảm ơn

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