DataTransfer API를 사용한 장벽 해소

사용자가 브라우저 창 외부에서 데이터를 공유할 수 있도록 합니다.

HTML5 Drag and Drop API클립보드 이벤트의 일부인 DataTransfer API에 대해 들어보셨을 것입니다. 소스 타겟과 수신 타겟 간에 데이터를 전송하는 데 사용할 수 있습니다.

브라우저 지원

  • 3
  • 12
  • 3.5
  • 4

소스

드래그 드롭 및 복사-붙여넣기 상호작용은 간단한 텍스트를 A에서 B로 전송하기 위해 페이지 내 상호작용에 자주 사용됩니다. 그러나 종종 간과되는 것은 이러한 동일한 상호작용을 사용하여 브라우저 창을 초월하는 기능입니다.

브라우저에 내장된 드래그 앤 드롭 상호작용과 복사-붙여넣기 상호작용은 웹 등의 다른 애플리케이션과 통신할 수 있으며 출처에 연결되지 않습니다. API는 데이터가 전송되는 위치에 따라 동작이 다른 여러 데이터 항목을 지원합니다. 웹 애플리케이션은 수신 이벤트를 수신할 때 전송된 데이터를 주고받을 수 있습니다.

이 기능은 데스크톱의 웹 애플리케이션에서의 공유 및 상호 운용성에 대한 사고 방식을 바꿀 수 있습니다. 더 이상 애플리케이션 간에 데이터를 전송할 때 긴밀하게 연결된 통합에 의존할 필요가 없습니다. 대신 사용자가 원하는 곳으로 데이터를 전송할 수 있는 전체 제어 권한을 부여할 수 있습니다.

DataTransfer API로 가능한 상호작용의 예 (동영상에는 사운드가 포함되지 않습니다.)

데이터 전송

시작하려면 드래그 앤 드롭 또는 복사-붙여넣기를 구현해야 합니다. 아래 예는 드래그 드롭 상호작용을 보여주지만 복사-붙여넣기 프로세스는 유사합니다. 드래그 앤 드롭 API에 익숙하지 않은 경우 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: contentEditable 요소 및 Google Docs, Microsoft Word와 같은 서식 있는 텍스트 (WYSIWYG) 편집기에서 HTML 페이로드를 렌더링합니다.
  • text/plain: 입력 요소의 값, 코드 편집기의 콘텐츠, text/html의 대체 값을 설정합니다.
  • text/uri-list: URL 표시줄 또는 브라우저 페이지에 드롭할 때 URL로 이동합니다. 디렉터리나 바탕화면에 드롭하면 URL 바로가기가 생성됩니다.

WYSIWYG 편집기에서 text/html를 널리 채택하여 매우 유용합니다. 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);

복사하여 붙여넣기를 사용하여 전송

다음은 복사-붙여넣기 상호작용과 함께 DataTransfer API를 사용하는 방법입니다. 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 (연결된 데이터) 표준이 적합합니다. 가볍고 자바스크립트에서 읽고 쓰기가 쉽습니다. 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 유형을 사용할 때는 일반적인 사물 유형으로 시작하거나 이벤트, 사람, MediaObject, 장소와 같이 사용 사례에 더 가까운 유형을 사용하거나 필요한 경우 MedicalEntity와 같이 매우 구체적인 유형을 사용할 수도 있습니다. TypeScript를 사용하는 경우 schema-dts 유형 정의의 인터페이스 정의를 사용할 수 있습니다.

JSON-LD 데이터를 송수신함으로써 보다 연결되고 개방적인 웹을 지원할 수 있습니다. 동일한 언어를 사용하는 애플리케이션을 사용하면 외부 애플리케이션과 긴밀히 통합할 수 있습니다. 복잡한 API 통합이 필요하지 않습니다. 전송되는 데이터에 필요한 모든 정보가 포함되어 있습니다.

캘린더의 일정을 좋아하는 할 일 앱으로 공유하거나 이메일에 가상 파일을 첨부하거나 연락처를 공유하는 등 웹 애플리케이션 간에 제한 없이 데이터를 전송할 수 있는 모든 가능성을 생각해 보세요. 멋지지 않을까요? 시작은 여러분에게서입니다. 🙌

문제

현재 DataTransfer API를 사용할 수 있지만 통합하기 전에 몇 가지 사항에 유의해야 합니다.

브라우저 호환성

데스크톱 브라우저는 모두 위에서 설명한 기술을 훌륭하게 지원하지만, 휴대기기는 지원하지 않습니다. 이 기법은 모든 주요 브라우저 (Chrome, Edge, Firefox, Safari)와 운영체제 (Android, ChromeOS, iOS, macOS, Ubuntu Linux, Windows)에서 테스트되었지만 안타깝게도 Android와 iOS는 테스트를 통과하지 못했습니다. 브라우저는 계속해서 개발되고 있지만 현재 이 기술은 데스크톱 브라우저로만 제한됩니다.

발견 가능성

드래그 드롭 및 복사-붙여넣기는 데스크톱 컴퓨터에서 작업할 때 시스템 수준의 상호작용으로, 40여 년 전 최초의 GUI에 기반을 두고 있습니다. 파일을 구성하는 데 이러한 상호작용을 얼마나 많이 사용했는지 생각해 보세요. 웹에서는 아직 흔하지 않습니다.

사용자에게 이 새로운 상호작용에 관해 교육해야 하며, 특히 지금까지 컴퓨터를 사용해 본 경험이 휴대기기로 국한된 사람들이 이러한 상호작용을 인지할 수 있도록 UX 패턴을 제시해야 합니다.

접근성

드래그 드롭은 그다지 쉽게 접근할 수 있는 상호작용은 아니지만 DataTransfer API는 복사-붙여넣기에서도 작동합니다. 복사-붙여넣기 이벤트를 수신 대기해야 합니다. 추가 작업도 많지 않으며 사용자들이 알아서 고마워할 것입니다.

보안 및 개인 정보 보호

이 기술을 사용할 때 유의해야 할 몇 가지 보안 및 개인 정보 보호 고려사항이 있습니다.

  • 클립보드 데이터는 사용자 기기의 다른 애플리케이션에서 사용할 수 있습니다.
  • 드래그하는 웹 애플리케이션은 데이터가 아닌 유형 키에 액세스할 수 있습니다. 데이터는 드롭 또는 붙여넣기 시에만 사용할 수 있습니다.
  • 수신된 데이터는 다른 사용자 입력처럼 취급해야 하며 사용하기 전에 삭제 및 검증해야 합니다.

Transmat 도우미 라이브러리 시작하기

애플리케이션에서 DataTransfer API를 사용해 보고 싶으신가요? GitHub의 Transmat 라이브러리를 살펴보세요. 이 오픈소스 라이브러리는 브라우저의 차이를 조정하고 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);

감사의 말

UnsplashLuba Ertel이 제공한 히어로 이미지입니다.