کاربر را قادر میسازد تا دادهها را فراتر از پنجره مرورگر به اشتراک بگذارد.
شاید در مورد DataTransfer API شنیده باشید، که بخشی از رویدادهای Drag and Drop API و Clipboard در HTML5 است. از آن میتوان برای انتقال دادهها بین منبع و مقصد دریافت استفاده کرد.
فعل و انفعالات کشیدن و رها کردن و کپی کردن و چسباندن اغلب برای تعاملات درون یک صفحه برای انتقال متن ساده از A به B استفاده میشوند. اما چیزی که اغلب نادیده گرفته میشود، توانایی استفاده از همین فعل و انفعالات برای فراتر رفتن از پنجره مرورگر است.
هم قابلیت کشیدن و رها کردن (drag-and-drop) داخلی مرورگر و هم قابلیت کپی و چسباندن (copy-paste) میتوانند با سایر برنامهها، چه تحت وب و چه غیر از آن، ارتباط برقرار کنند و به هیچ منبعی وابسته نیستند. این 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: محتوای HTML را در عناصرcontentEditableو ویرایشگرهای متن غنی (WYSIWYG) مانند Google Docs، Microsoft Word و موارد دیگر رندر میکند. -
text/plain:مقدار عناصر ورودی، محتوای ویرایشگرهای کد و جایگزینtext/htmlرا تنظیم میکند. -
text/uri-list: هنگام رها کردن در نوار آدرس یا صفحه مرورگر، به آدرس اینترنتی هدایت میشود. هنگام رها کردن در یک دایرکتوری یا دسکتاپ، یک میانبر آدرس اینترنتی ایجاد میشود.
پذیرش گسترده text/html توسط ویرایشگرهای WYSIWYG آن را بسیار مفید میکند. همانند اسناد HTML، میتوانید منابع را با استفاده از URLهای داده یا URLهای قابل دسترس عمومی جاسازی کنید. این روش با خروجی گرفتن از تصاویر (مثلاً از یک canvas) به ویرایشگرهایی مانند 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 (دادههای پیوندی) کاندیدای بسیار خوبی برای این کار است. این استاندارد سبک است و خواندن و نوشتن در جاوا اسکریپت در آن آسان است. 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 مورد علاقهتان، پیوست کردن فایلهای مجازی به ایمیلها، اشتراکگذاری مخاطبین. خیلی عالی میشد، نه؟ این از شما شروع میشود! 🙌
نگرانیها
اگرچه رابط برنامهنویسی کاربردی انتقال داده (DataTransfer API) امروزه در دسترس است، اما نکاتی وجود دارد که باید قبل از ادغام از آنها آگاه باشید.
سازگاری با مرورگرها
مرورگرهای دسکتاپ همگی از تکنیکی که در بالا توضیح داده شد پشتیبانی خوبی دارند، در حالی که دستگاههای تلفن همراه این پشتیبانی را ندارند. این تکنیک روی تمام مرورگرهای اصلی (کروم، اج، فایرفاکس، سافاری) و سیستم عاملها (اندروید، کروم او اس، آی او اس، مک او اس، اوبونتو لینوکس و ویندوز) آزمایش شده است، اما متأسفانه اندروید و آی او اس از این آزمایش سربلند بیرون نیامدند. در حالی که مرورگرها همچنان در حال توسعه هستند، در حال حاضر این تکنیک فقط به مرورگرهای دسکتاپ محدود شده است.
قابلیت کشف
کشیدن و رها کردن و کپی کردن و چسباندن، تعاملات سطح سیستم هنگام کار با رایانه رومیزی هستند که ریشه در اولین رابطهای کاربری گرافیکی بیش از ۴۰ سال پیش دارند. به این فکر کنید که چند بار از این تعاملات برای سازماندهی فایلها استفاده کردهاید. این هنوز در وب خیلی رایج نیست.
شما باید کاربران را در مورد این تعامل جدید آموزش دهید و الگوهای UX را ارائه دهید تا این امر قابل تشخیص باشد، به خصوص برای افرادی که تجربه آنها با رایانه تاکنون محدود به دستگاههای تلفن همراه بوده است.
دسترسیپذیری
کشیدن و رها کردن یک تعامل خیلی قابل دسترس نیست، اما API انتقال داده با کپی-چسباندن نیز کار میکند. مطمئن شوید که به رویدادهای کپی-چسباندن گوش میدهید. کار اضافی زیادی لازم ندارد و کاربران شما از اضافه کردن آن سپاسگزار خواهند بود.
امنیت و حریم خصوصی
هنگام استفاده از این تکنیک، باید از برخی ملاحظات امنیتی و حریم خصوصی آگاه باشید.
- دادههای کلیپبورد برای سایر برنامههای موجود در دستگاه کاربر در دسترس است.
- برنامههای وب که در حال کشیدن و رها کردن (drag) آنها هستید، به کلیدهای تایپ دسترسی دارند، نه به دادهها. دادهها فقط با رها کردن یا چسباندن (paste) در دسترس قرار میگیرند.
- با دادههای دریافتی باید مانند هر ورودی کاربر دیگر رفتار شود؛ قبل از استفاده، پاکسازی و اعتبارسنجی شوند.
شروع کار با کتابخانه کمکی Transmat
آیا از استفاده از API انتقال داده (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);