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 nói về DataTransfer API, tức là thuộc API Kéo và thả HTML5Sự kiện trên bảng nhớ tạm. Chiến dịch này có thể được dùng để truyền dữ liệu giữa đích đến và đích.

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 được dùng cho các tương tác trên 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 chính những tương tác này để vượt ra ngoài cửa sổ trình duyệt.

Cả tính năng tương tác kéo và thả tích hợp sẵn của trình duyệt lẫn sao chép và dán đều có thể giao tiếp với các ứng dụng khác, web hoặc loại 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 các hành vi khác nhau dựa trên nơi dữ liệu được chuyển đến. Thông tin ứng dụng web có thể gửi và nhận dữ liệu đã chuyển khi theo dõi các sự kiện đến.

Khả 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 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 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 ở 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 bằng DataTransfer API. (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. Ví dụ bên dưới hiển thị các tương tác kéo-thả, nhưng quy trình sao chép-dán cũng tương tự như vậy. Nếu bạn chưa biết gì về API Kéo và thả, có một bài viết hay giải thích tính năng Kéo và thả HTML5, giải thích chi tiết.

Bằng cách cung cấp dữ liệu khoá kiểu 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 các trình chỉnh sửa WYSIWYG, trình soạn thảo văn bản và trình duyệt đều phản hồi lại thuộc tính "gốc" Các loại mime 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. Hàm này trả về một bản sao 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 chuyển sẽ hoạt động gần giống như quá trình cung cấp dữ liệu. Nghe sự kiện nhận (drop hoặc paste) rồi đọ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à có nội dung phong phú Trình chỉnh sửa văn bản (WYSIWYG) như Google Tài liệu, Microsoft Word và các trình chỉnh sửa khác.
  • text/plain: Thiết lập 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à thành phần dự phòng từ text/html.
  • text/uri-list: Chuyển đến URL khi thả trên thanh URL hoặc trang trình duyệt. Một URL lối tắt sẽ được tạo khi thả vào thư mục hoặc màn hì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. Như trong HTML tài liệu, bạn có thể nhúng tài nguyên bằng cách sử dụng URL dữ liệu hoặc công khai URL có thể truy cập. Cách này hiệu quả khi xuất hình ảnh (ví dụ: từ canvas) sang các công cụ 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 API DataTransfer với hoạt động tương tác sao chép và dán. 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 đượ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ạ 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ó trong tầm kiểm soát, nhưng cũng giới hạn 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 bạn muốn kết nối với các ứng dụng của bên thứ ba trên web thì bạn cần 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 lựa chọn tuyệt vời cho mục tiêu này. Đó là gọn nhẹ và dễ đọc và dễ ghi vào JavaScript. Schema.org chứa nhiều định nghĩa trước mà bạn có thể sử dụng, 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 với loại Thing chung, hoặc sử dụng tính năng gần với trường hợp sử dụng của bạn hơn như Sự kiện, Người, MediaObject, Địa điểm hoặc thậm chí là các loại cụ thể như MedicalEntity nếu cần. Khi sử dụng TypeScript, bạn có thể sử dụng định nghĩa giao diện từ các đị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à được kết nối nhiều hơn. Bằng ứng dụng nói cùng một ngôn ngữ, bạn có thể tích hợp sâu với các . Không cần tích hợp API phức tạp; tất cả thông tin cần thiết có trong dữ liệu được chuyển.

Hãy suy nghĩ về tất cả các khả năng chuyển dữ liệu giữa bất kỳ ứng dụng (web) nào mà không cần hạn chế: chia sẻ sự kiện từ lịch với ứ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? Hành trình này bắt đầu từ bạn! 🙌

Mối quan tâm

Mặc dù hiện tại đã 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ả trình duyệt dành cho máy tính đều hỗ trợ tuyệt vời cho kỹ thuật được mô tả ở trên, trong khi thiết bị di động thì hỗ trợ 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 rất tiếc là Android và iOS không vượt qua được quy trình kiểm tra. Mặc dù các trình duyệt vẫn tiếp tục phát triển, nhưng hiện tại, kỹ thuật này còn bị hạn chế cho trình duyệt dành cho máy tính.

Tiềm năng khám phá

Kéo-thả và sao chép-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, với bắt nguồn từ GUI đầu tiên cách đây hơn 40 năm. Nghĩ xem bạn có bao nhiêu lần đã sử dụng các tương tác này để sắp xếp tệp. Điều này vẫn chưa phổ biến trên web.

Bạn sẽ cần cho người dùng biết về hoạt động tương tác mới này cũng như đưa ra các mẫu trải nghiệm người dùng để có thể nhận dạng, đặc biệt đối với những người có kinh nghiệm sử dụng máy tính chỉ giới hạ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ễ tiếp cận, nhưng DataTransfer API cũng hoạt động với sao chép và dán. Đảm bảo bạn nghe các sự kiện sao chép và dán. Bạn không phải làm gì thêm, và người dùng của bạn sẽ biết ơn bạn đã thêm nó.

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.

  • Dữ liệu vào 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 chứ không phải dữ liệu. Chỉ dữ liệu sẽ có khi thả hoặc dán.
  • Dữ liệu nhận được 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ình trợ giúp Transmat

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

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 Không hiển thị màn hình.