Разрушение барьеров с помощью DataTransfer API

Предоставьте пользователю возможность обмениваться данными за пределами окна браузера.

Возможно, вы слышали об API DataTransfer , который является частью HTML5 Drag and Drop API и событий буфера обмена . Его можно использовать для передачи данных между источником и получателем.

Поддержка браузера

  • 3
  • 12
  • 3,5
  • 4

Источник

Взаимодействия перетаскивания и копирования-вставки часто используются для взаимодействий внутри страницы для передачи простого текста из A в B. Но что часто упускается из виду, так это возможность использовать эти же взаимодействия для выхода за пределы окна браузера.

Как встроенные в браузер возможности перетаскивания, так и копирование-вставка могут взаимодействовать с другими приложениями, веб- или другими, и не привязаны к какому-либо источнику. API поддерживает несколько записей данных с различным поведением в зависимости от того, куда передаются данные. Ваше веб-приложение может отправлять и получать переданные данные при прослушивании входящих событий.

Эта возможность может изменить наше представление о совместном использовании и взаимодействии веб-приложений на настольных компьютерах. Передача данных между приложениями больше не требует тесной интеграции. Вместо этого вы можете предоставить пользователям полный контроль над передачей данных туда, куда они пожелают.

Пример взаимодействия, возможного с API DataTransfer. (Видео без звука.)

Перенос данных

Для начала вам нужно реализовать перетаскивание или копирование-вставку. В примерах ниже показано взаимодействие перетаскивания, но процесс копирования и вставки аналогичен. Если вы не знакомы с API перетаскивания, есть отличная статья , объясняющая HTML5 Drag and Drop , в которой объясняются все тонкости.

Предоставляя данные с ключами типа 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-адреса или страницу браузера. Ярлык 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; вся необходимая информация включена в передаваемые данные.

Подумайте обо всех возможностях передачи данных между любыми (веб-приложениями) без ограничений: обмен событиями из календаря в любимое приложение ToDo, прикрепление виртуальных файлов к электронным письмам, обмен контактами. Это было бы здорово, правда? Это начинается с тебя! 🙌

Обеспокоенность

Хотя API DataTransfer доступен уже сегодня, перед интеграцией следует учитывать некоторые моменты.

Совместимость с браузером

Все настольные браузеры отлично поддерживают описанный выше метод, а мобильные устройства — нет. Этот метод был протестирован во всех основных браузерах (Chrome, Edge, Firefox, Safari) и операционных системах (Android, ChromeOS, iOS, macOS, Ubuntu Linux и Windows), но, к сожалению, Android и iOS не прошли тест. Хотя браузеры продолжают развиваться, на данный момент этот метод ограничен только браузерами для настольных компьютеров.

Обнаруживаемость

Перетаскивание и копирование — это взаимодействия на уровне системы при работе на настольном компьютере, уходящие корнями в первые графические интерфейсы, появившиеся более 40 лет назад. Подумайте, сколько раз вы использовали эти взаимодействия для организации файлов. Это пока не очень распространено в сети.

Вам нужно будет рассказать пользователям об этом новом взаимодействии и придумать шаблоны UX, чтобы сделать его узнаваемым, особенно для людей, чей опыт работы с компьютерами до сих пор ограничивался мобильными устройствами.

Доступность

Перетаскивание — не очень доступное взаимодействие, но API DataTransfer также работает с копированием. Обязательно слушайте события копирования и вставки. Это не потребует много дополнительной работы, и ваши пользователи будут вам благодарны за это.

Безопасность и конфиденциальность

При использовании этого метода следует учитывать некоторые соображения безопасности и конфиденциальности.

  • Данные буфера обмена доступны другим приложениям на устройстве пользователя.
  • Веб-приложения, которые вы перетаскиваете, имеют доступ к клавишам типа, а не к данным. Данные становятся доступными только при удалении или вставке.
  • Полученные данные следует рассматривать как любой другой пользовательский ввод; продезинфицировать и проверить перед использованием.

Начало работы со вспомогательной библиотекой Transmat

Вам нравится использовать DataTransfer API в вашем приложении? Рассмотрите возможность взглянуть на библиотеку 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 .