사용자가 브라우저 창을 넘어 데이터를 공유할 수 있도록 합니다.
HTML5 드래그 앤 드롭 API 및 클립보드 이벤트의 일부인 DataTransfer API에 대해 들어보셨을 수도 있습니다. 소스와 수신 대상 간에 데이터를 전송하는 데 사용할 수 있습니다.
드래그 앤 드롭 및 복사-붙여넣기 상호작용은 페이지 내에서 A에서 B로 간단한 텍스트를 전송하는 데 자주 사용됩니다. 하지만 간과되는 경우가 많은 것은 이러한 동일한 상호작용을 사용하여 브라우저 창을 넘어설 수 있다는 점입니다.
브라우저의 기본 제공 드래그 앤 드롭과 복사-붙여넣기 상호작용은 다른 애플리케이션(웹 또는 기타)과 통신할 수 있으며 출처에 연결되지 않습니다. 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요소와 서식 있는 텍스트(WYSIWYG) 편집기(예: Google Docs, Microsoft Word 등)에서 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 (연결된 데이터) 표준이 이 경우에 적합합니다. 경량이며 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 통합이 필요하지 않습니다. 필요한 모든 정보가 전송된 데이터에 포함되어 있습니다.
제한 없이 모든 (웹) 애플리케이션 간에 데이터를 전송할 수 있는 모든 가능성을 생각해 보세요. 캘린더의 일정을 즐겨 사용하는 할 일 앱에 공유하고, 이메일에 가상 파일을 첨부하고, 연락처를 공유하는 등 다양한 작업을 할 수 있습니다. 그럼 좋겠죠? 이러한 노력은 여러분으로부터 시작됩니다. 🙌
문제
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);
감사의 말씀
Unsplash의 Luba Ertel이 촬영한 히어로 이미지