Cho phép người dùng chia sẻ dữ liệu ra ngoài cửa sổ trình duyệt.
Có thể bạn đã nghe nói về DataTransfer API. Đây là một phần của HTML5 Drag and Drop API và Clipboard events. Bạn có thể dùng công cụ này để chuyển dữ liệu giữa nguồn và đích nhận.
Tương tác kéo và thả cũng như sao chép và dán thường được dùng cho các 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 chính những hoạt động tương tác này để vượt ra ngoài cửa sổ trình duyệt.
Cả thao tác kéo và thả tích hợp sẵn của trình duyệt cũng như thao tác sao chép và dán đều có thể giao tiếp với các ứng dụng khác (trên web hoặc không) và không bị ràng buộc 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 được chuyển khi lắng 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. Bạn không cần phải dựa vào các hoạt động tích hợp liên kết chặt chẽ để chuyển dữ liệu giữa các ứng dụng nữa. Thay vào đó, bạn có thể trao cho người dùng toàn quyền kiểm soát việc chuyển dữ liệu đến bất cứ nơi nào họ muốn.
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 minh hoạ hoạt động 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ả, thì có một bài viết hay giải thích về tính năng Kéo và thả của HTML5, trong đó giải thích mọi khía cạnh của tính năng này.
Bằng cách cung cấp dữ liệu có khoá loại MIME, bạn có thể tương tác thoải mái 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 "nguyên thuỷ" được 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 trả về một thực thể của DataTransfer. Như bạn thấy, đôi khi đối tượng này được trả về theo các thuộc tính có tên khác.
Việc nhận dữ liệu chuyển gần giống như việc cung cấp dữ liệu. Lắng nghe các sự kiện nhận (drop hoặc paste) và đọc các khoá. Khi kéo 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: Kết xuất tải trọng HTML trong các phần tửcontentEditablevà 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 chỉnh sửa 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 bạn thả vào một thư mục hoặc màn hình nền.
Việc các trình chỉnh sửa WYSIWYG áp dụng rộng rãi text/html khiến nó trở nên 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. Điều này hoạt động 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 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 trả về theo một thuộc tính có tên là clipboardData cho các sự kiện trê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() và 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ù các định dạng tuỳ chỉnh rất phù hợp để giao tiếp giữa các ứng dụng mà bạ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ổ biến.
Tiêu chuẩn JSON-LD (Dữ liệu được liên kết) là một lựa chọn phù hợp cho việc này. Đây là một định dạng gọn nhẹ, dễ đọc và ghi trong JavaScript. Schema.org có 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ể dùng các đị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 loại gần với trường hợp sử dụng của bạn hơn, chẳng hạn như Event, Person, MediaObject, Place hoặc thậm chí là các loại có tính chất cụ thể cao 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 mở và có nhiều kết nối hơn. Khi các ứng dụng sử dụng cùng một ngôn ngữ, bạn có thể tạo các mối tích hợp sâu với các ứng dụng bên ngoài. Bạn không cần tích hợp API phức tạp; mọi 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ó hạn chế: chia sẻ sự kiện từ lịch sang ứng dụng ToDo yêu thích của bạn, đính kèm tệp ảo vào email, chia sẻ danh bạ. Thật tuyệt vời 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ó sẵn, 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 trên máy tính đều hỗ trợ tốt kỹ thuật được mô tả ở trên, trong khi các 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 tiếc là Android và iOS không vượt qua được bài 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 chỉ giới hạn ở các 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à những hoạt động ở cấp hệ thống khi làm việc trên máy tính để bàn, có nguồn gốc từ các GUI đầu tiên cách đây hơn 40 năm. Hãy nghĩ xem bạn đã sử dụng những thao tác này bao nhiêu lần để 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 để giúp người dùng nhận ra cách tương tác này, đặc biệt là đối với 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
Kéo và thả không phải là một hoạt động tương tác dễ tiếp cận, nhưng DataTransfer API cũng hoạt động với thao tác sao chép và dán. Đảm bảo bạn theo dõi các sự kiện sao chép và dán. Bạn không cần phải làm thêm nhiều việc và người dùng sẽ rất biết ơn bạn vì đã thêm tính năng này.
Bảo mật và quyền riêng tư
Bạn nên lưu ý một số vấn đề về tính 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ể truy cập vào dữ liệu trên bảng nhớ tạm.
- Các ứng dụng web mà bạn đang kéo qua 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 bạn thả hoặc dán.
- Bạn nên xử lý dữ liệu nhận được như mọi dữ liệu đầu vào khác của người dùng; làm sạch và xác thực trước khi sử dụng.
Làm quen với thư viện trợ lý 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 xem thư viện Transmat trên GitHub. Thư viện mã nguồn mở này điều chỉnh sự khác biệt giữa các 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 cho các vùng thả làm nổi bật và cho phép bạn tích hợp các thao tác chuyển dữ liệu giữa các hoạt động 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.