Дайте возможность пользователю обмениваться данными за пределами окна браузера.
Возможно, вы слышали об API DataTransfer , который является частью HTML5 Drag and Drop API и событий буфера обмена . Его можно использовать для передачи данных между источником и получателем.
Операции перетаскивания и копирования-вставки часто используются для взаимодействия внутри страницы, чтобы перенести простой текст из пункта А в пункт Б. Но часто упускается из виду возможность использовать эти же операции для выхода за пределы окна браузера.
Встроенные в браузер функции перетаскивания и копирования/вставки могут взаимодействовать с другими приложениями, как веб-приложениями, так и другими, и не привязаны к какому-либо источнику. API поддерживает несколько записей данных с различным поведением в зависимости от того, куда они передаются. Ваше веб-приложение может отправлять и получать передаваемые данные, прослушивая входящие события.
Эта возможность может изменить наше представление о совместном доступе и взаимодействии веб-приложений на настольных компьютерах. Передача данных между приложениями больше не обязательно должна зависеть от тесной интеграции. Вместо этого вы можете предоставить пользователям полный контроль над передачей данных туда, куда им удобно.
Передача данных
Для начала вам потребуется реализовать перетаскивание или копирование и вставку. В примерах ниже показано взаимодействие с перетаскиванием, но процесс копирования и вставки аналогичен. Если вы не знакомы с API Drag and Drop, есть отличная статья, объясняющая особенности перетаскивания в HTML5 .
Предоставляя данные с ключами в формате MIME , вы можете свободно взаимодействовать с внешними приложениями. Большинство WYSIWYG-редакторов, текстовых редакторов и браузеров поддерживают «примитивные» MIME-типы, используемые в примере ниже.
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');
});
Обратите внимание на свойство event.dataTransfer . Оно возвращает экземпляр DataTransfer . Как вы увидите, этот объект иногда возвращается свойствами с другими именами.
Получение данных работает практически так же, как и их предоставление. Отслеживайте события получения ( drop или paste ) и считывайте ключи. При перетаскивании элемента браузер имеет доступ только к ключам type данных. Сами данные доступны только после перетаскивания.
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();
});
В различных приложениях широко поддерживаются три типа MIME:
-
text/html: отображает полезную нагрузку HTML в элементахcontentEditableи редакторах форматированного текста (WYSIWYG), таких как Google Docs, Microsoft Word и других. -
text/plain:задает значение элементов ввода, содержимое редакторов кода и откат отtext/html. -
text/uri-list: Переходит по URL-адресу при перетаскивании в адресную строку или на страницу браузера. При перетаскивании в каталог или на рабочий стол будет создан ярлык URL-адреса.
Широкое распространение text/html в WYSIWYG-редакторах делает его чрезвычайно полезным. Как и в HTML-документах, вы можете встраивать ресурсы, используя URL-адреса данных или общедоступные URL-адреса. Это хорошо подходит для экспорта визуальных данных (например, из холста) в редакторы, такие как Google Docs.
const redPixel = 'data:image/gif;base64,R0lGODdhAQABAPAAAP8AAAAAACwAAAAAAQABAAACAkQBADs=';
const html = '<img src="' + redPixel + '" width="100" height="100" alt="" />';
event.dataTransfer.setData('text/html', html);
Перенос методом копирования и вставки
Ниже показано использование API DataTransfer с функциями копирования и вставки. Обратите внимание, что объект DataTransfer возвращается свойством clipboardData для событий буфера обмена.
// 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);
}
});
Пользовательские форматы данных
Вы не ограничены примитивными типами MIME и можете использовать любой ключ для идентификации передаваемых данных. Это может быть полезно для кроссбраузерного взаимодействия внутри вашего приложения. Как показано ниже, вы можете передавать более сложные данные с помощью функций 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);
}
});
Подключение к Интернету
Хотя пользовательские форматы отлично подходят для обмена данными между приложениями, находящимися под вашим контролем, они также ограничивают возможности пользователя при передаче данных в приложения, не использующие ваш формат. Если вы хотите подключаться к сторонним приложениям через Интернет, вам необходим универсальный формат данных.
Стандарт JSON-LD (Linked Data) — отличный кандидат для этой цели. Он лёгкий и легко читается и записывается в JavaScript. Schema.org содержит множество предопределённых типов данных, которые можно использовать, а также доступны пользовательские определения схем.
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));
При использовании типов Schema.org вы можете начать с универсального типа Thing или использовать что-то более подходящее для вашего случая, например Event , Person , MediaObject , Place , или даже более специфичные типы, например MedicalEntity , если это необходимо. При использовании TypeScript вы можете использовать определения интерфейсов из определений типов schema-dts .
Передавая и получая данные JSON-LD, вы поддерживаете более связный и открытый Интернет. Благодаря приложениям, говорящим на одном языке, вы можете создавать глубокую интеграцию с внешними приложениями. Нет необходимости в сложной интеграции API; вся необходимая информация включена в передаваемые данные.
Подумайте о всех возможностях передачи данных между любыми (веб) приложениями без ограничений: делитесь событиями из календаря в любимом приложении «Дела», прикрепляйте виртуальные файлы к электронным письмам, делитесь контактами. Было бы здорово, правда? Всё начинается с вас! 🙌
Обеспокоенность
Несмотря на то, что API DataTransfer доступен уже сегодня, перед интеграцией следует учесть некоторые моменты.
Совместимость с браузерами
Все браузеры настольных компьютеров отлично поддерживают описанную выше технологию, в отличие от мобильных устройств. Эта технология была протестирована во всех основных браузерах (Chrome, Edge, Firefox, Safari) и операционных системах (Android, ChromeOS, iOS, macOS, Ubuntu Linux и Windows), но, к сожалению, Android и iOS её не прошли. Хотя браузеры продолжают развиваться, на данный момент эта технология доступна только для настольных компьютеров.
Открываемость
Перетаскивание и копирование/вставка — это системные взаимодействия при работе на настольном компьютере, корни которых уходят в первые графические интерфейсы более 40 лет назад. Подумайте, сколько раз вы использовали эти взаимодействия для организации файлов. В интернете это пока не очень распространено.
Вам нужно будет объяснить пользователям особенности этого нового взаимодействия и придумать шаблоны UX, которые сделают его узнаваемым, особенно для людей, чей опыт работы с компьютерами до сих пор ограничивался мобильными устройствами.
Доступность
Перетаскивание — не очень удобный способ взаимодействия, но API DataTransfer также поддерживает копирование и вставку. Убедитесь, что вы отслеживаете события копирования и вставки. Это не требует особых усилий, и ваши пользователи будут вам благодарны за это.
Безопасность и конфиденциальность
При использовании этой техники следует учитывать некоторые соображения безопасности и конфиденциальности.
- Данные буфера обмена доступны другим приложениям на устройстве пользователя.
- Веб-приложения, над которыми вы перетаскиваете курсор, имеют доступ к ключам типа, но не к самим данным. Данные становятся доступны только при перетаскивании или вставке.
- Полученные данные следует обрабатывать так же, как и любые другие введенные пользователем данные; перед использованием их следует очищать и проверять.
Начало работы с вспомогательной библиотекой Transmat
Хотите использовать API DataTransfer в своём приложении? Рекомендуем обратить внимание на библиотеку Transmat на GitHub . Эта библиотека с открытым исходным кодом выравнивает различия между браузерами, предоставляет утилиты JSON-LD, содержит наблюдателя для реагирования на события передачи, подсвечивая области перетаскивания, и позволяет интегрировать операции передачи данных между существующими реализациями перетаскивания.
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);
Благодарности
Главное изображение Любы Эртель на Unsplash .