Pokonywanie barier za pomocą interfejsu DataTransfer API

Umożliwia użytkownikowi udostępnianie danych poza oknem przeglądarki.

Być może znasz interfejs DataTransfer API, który jest częścią interfejsu HTML5 Drag and Drop API i zdarzeń schowka. Może służyć do przesyłania danych między źródłem a miejscem docelowym.

Browser Support

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

Source

Interakcje typu „przeciągnij i upuść” oraz „kopiuj i wklej” są często używane na stronie do przenoszenia prostego tekstu z miejsca A do miejsca B. Często jednak pomija się możliwość wykorzystania tych samych interakcji poza oknem przeglądarki.

Zarówno wbudowana w przeglądarkę funkcja przeciągania i upuszczania, jak i interakcje związane z kopiowaniem i wklejaniem mogą komunikować się z innymi aplikacjami (internetowymi i nieinternetowymi) i nie są powiązane z żadnym źródłem. Interfejs API obsługuje wiele wpisów danych o różnym działaniu w zależności od tego, gdzie dane są przesyłane. Aplikacja internetowa może wysyłać i odbierać przesyłane dane, gdy nasłuchuje zdarzeń przychodzących.

Ta funkcja może zmienić sposób, w jaki myślimy o udostępnianiu i współdziałaniu w aplikacjach internetowych na komputerach. Przenoszenie danych między aplikacjami nie musi już opierać się na ściśle powiązanych integracjach. Zamiast tego możesz dać użytkownikom pełną kontrolę nad przenoszeniem danych w dowolne miejsce.

Przykład interakcji możliwych dzięki interfejsowi DataTransfer API. (Film nie zawiera dźwięku).

Przenoszenie danych

Aby rozpocząć, musisz wdrożyć funkcję przeciągania i upuszczania lub kopiowania i wklejania. Przykłady poniżej pokazują interakcje typu „przeciągnij i upuść”, ale proces kopiowania i wklejania jest podobny. Jeśli nie znasz interfejsu Drag and Drop API, przeczytaj ten artykuł wyjaśniający funkcję przeciągania i upuszczania w HTML5.

Dostarczając dane kluczowe typu MIME, możesz swobodnie wchodzić w interakcje z aplikacjami zewnętrznymi. Większość edytorów WYSIWYG, edytorów tekstu i przeglądarek reaguje na „podstawowe” typy MIME użyte w przykładzie poniżej.

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');
});

Zwróć uwagę na właściwość event.dataTransfer. Zwraca instancję klasy DataTransfer. Jak widać, ten obiekt jest czasami zwracany przez właściwości o innych nazwach.

Odbieranie danych działa prawie tak samo jak ich udostępnianie. Nasłuchuj zdarzeń odbioru (drop lub paste) i odczytuj klucze. Podczas przeciągania elementu przeglądarka ma dostęp tylko do kluczy type danych. Dostęp do samych danych jest możliwy dopiero po zakończeniu dropu.

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

Trzy typy MIME są powszechnie obsługiwane w aplikacjach:

  • text/html: renderuje ładunek HTML w elementach contentEditable i edytorach tekstu sformatowanego (WYSIWYG), takich jak Dokumenty Google, Microsoft Word i inne.
  • text/plain: Ustawia wartość elementów wejściowych, zawartość edytorów kodu i wartość domyślną z text/html.
  • text/uri-list: przechodzi do adresu URL po upuszczeniu go na pasku adresu lub na stronie przeglądarki. Po upuszczeniu w katalogu lub na pulpicie zostanie utworzony skrót URL.

Powszechne stosowanie text/html przez edytory WYSIWYG sprawia, że jest to bardzo przydatne narzędzie. Podobnie jak w przypadku dokumentów HTML możesz osadzać zasoby za pomocą adresów URL danych lub publicznie dostępnych adresów URL. Jest to przydatne podczas eksportowania elementów wizualnych (np. z elementu canvas) do edytorów takich jak Dokumenty Google.

const redPixel = 'data:image/gif;base64,R0lGODdhAQABAPAAAP8AAAAAACwAAAAAAQABAAACAkQBADs=';
const html = '<img src="' + redPixel + '" width="100" height="100" alt="" />';
event.dataTransfer.setData('text/html', html);

Przenoszenie za pomocą kopiowania i wklejania

Poniżej pokazujemy, jak używać interfejsu DataTransfer API w interakcjach typu „kopiuj i wklej”. Zwróć uwagę, że w przypadku zdarzeń schowka obiekt DataTransfer jest zwracany przez właściwość o nazwie 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);
  }
});

Niestandardowe formaty danych

Nie musisz ograniczać się do podstawowych typów MIME, ale możesz użyć dowolnego klucza do identyfikowania przesyłanych danych. Może to być przydatne w przypadku interakcji w aplikacji w różnych przeglądarkach. Jak widać poniżej, bardziej złożone dane możesz przenieść za pomocą funkcji JSON.stringify() i 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);
  }
});

Łączenie internetu

Formaty niestandardowe świetnie sprawdzają się w komunikacji między aplikacjami, nad którymi masz kontrolę, ale ograniczają użytkownika podczas przesyłania danych do aplikacji, które nie korzystają z Twojego formatu. Jeśli chcesz łączyć się z aplikacjami innych firm w internecie, potrzebujesz uniwersalnego formatu danych.

Świetnie nadaje się do tego standard JSON-LD (Linked Data). Jest lekki i łatwy do odczytu i zapisu w JavaScript. Schema.org zawiera wiele predefiniowanych typów, których można używać. Możesz też tworzyć własne definicje schematów.

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));

Korzystając z typów Schema.org, możesz zacząć od ogólnego typu Thing lub użyć typu bardziej zbliżonego do Twojego przypadku, np. Event, Person, MediaObject, Place, a w razie potrzeby nawet bardzo szczegółowych typów, takich jak MedicalEntity. Jeśli używasz TypeScriptu, możesz korzystać z definicji interfejsów z definicji typów schema-dts.

Przesyłając i odbierając dane JSON-LD, przyczyniasz się do tworzenia bardziej połączonej i otwartej sieci. Dzięki temu, że aplikacje „mówią” tym samym językiem, możesz tworzyć zaawansowane integracje z aplikacjami zewnętrznymi. Nie musisz przeprowadzać skomplikowanych integracji interfejsu API – wszystkie potrzebne informacje są zawarte w przenoszonych danych.

Pomyśl o wszystkich możliwościach przesyłania danych między dowolnymi aplikacjami (internetowymi) bez ograniczeń: udostępnianie wydarzeń z kalendarza w ulubionej aplikacji do zarządzania zadaniami, załączanie wirtualnych plików do e-maili, udostępnianie kontaktów. To byłoby świetne, prawda? Zacznij od siebie. 🙌

Potencjalne problemy

Interfejs DataTransfer API jest dostępny od dziś, ale przed jego zintegrowaniem warto pamiętać o kilku kwestiach.

Zgodność z przeglądarką

Przeglądarki na komputery stacjonarne w pełni obsługują opisaną powyżej technikę, a urządzenia mobilne – nie. Technika została przetestowana we wszystkich głównych przeglądarkach (Chrome, Edge, Firefox, Safari) i systemach operacyjnych (Android, ChromeOS, iOS, macOS, Ubuntu Linux i Windows), ale niestety nie przeszła testu na urządzeniach z Androidem i iOS. Przeglądarki są wciąż rozwijane, ale obecnie ta technika jest ograniczona tylko do przeglądarek na komputery.

Widoczność kanału i treści

Przeciąganie i upuszczanie oraz kopiowanie i wklejanie to interakcje na poziomie systemu podczas pracy na komputerze stacjonarnym, które mają swoje korzenie w pierwszych graficznych interfejsach użytkownika sprzed ponad 40 lat. Zastanów się, ile razy używasz tych interakcji do porządkowania plików. Nie jest to jeszcze zbyt powszechne w internecie.

Musisz poinformować użytkowników o tej nowej interakcji i opracować wzorce UX, które sprawią, że będzie ona rozpoznawalna, zwłaszcza dla osób, które do tej pory korzystały z komputerów tylko na urządzeniach mobilnych.

Ułatwienia dostępu

Przeciąganie i upuszczanie nie jest zbyt przystępną interakcją, ale interfejs DataTransfer API działa też z kopiowaniem i wklejaniem. Upewnij się, że nasłuchujesz zdarzeń kopiowania i wklejania. Nie wymaga to wiele dodatkowej pracy, a użytkownicy będą Ci wdzięczni za dodanie tej funkcji.

Bezpieczeństwo i prywatność

Podczas korzystania z tej techniki należy pamiętać o pewnych kwestiach związanych z bezpieczeństwem i prywatnością.

  • Dane ze schowka są dostępne dla innych aplikacji na urządzeniu użytkownika.
  • Aplikacje internetowe, które przeciągasz, mają dostęp do kluczy typu, a nie do danych. Dane stają się dostępne dopiero po upuszczeniu lub wklejeniu.
  • Otrzymane dane należy traktować jak każde inne dane wejściowe użytkownika – przed użyciem należy je oczyścić i zweryfikować.

Pierwsze kroki z biblioteką pomocniczą Transmat

Czy chcesz używać interfejsu DataTransfer API w swojej aplikacji? Zapoznaj się z biblioteką Transmat w GitHubie. Ta biblioteka open source ujednolica różnice między przeglądarkami, udostępnia narzędzia JSON-LD, zawiera obserwatora, który reaguje na zdarzenia przesyłania, aby wyróżniać obszary docelowe, i umożliwia integrację operacji przesyłania danych z istniejącymi implementacjami przeciągania i upuszczania.

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);

Podziękowania

Baner powitalny autorstwa Luby Ertel na stronie Unsplash.