شکستن موانع با استفاده از DataTransfer API

کاربر را قادر می سازد تا داده ها را فراتر از پنجره مرورگر به اشتراک بگذارد.

ممکن است درباره DataTransfer API شنیده باشید که بخشی از رویدادهای HTML5 Drag and Drop API و Clipboard است. می توان از آن برای انتقال داده ها بین هدف های منبع و دریافت کننده استفاده کرد.

پشتیبانی مرورگر

  • کروم: 3.
  • لبه: 12.
  • فایرفاکس: 3.5.
  • سافاری: 4.

منبع

تعاملات کشیدن-دراپ و کپی-پیست اغلب برای تعاملات درون یک صفحه برای انتقال متن ساده از A به B استفاده می شود. اما چیزی که اغلب نادیده گرفته می شود، توانایی استفاده از همین تعاملات برای فراتر رفتن از پنجره مرورگر است.

هر دو تعامل داخلی مرورگر با کشیدن و رها کردن و کپی پیست می توانند با برنامه های کاربردی دیگر، وب یا موارد دیگر ارتباط برقرار کنند و به هیچ منبعی مرتبط نیستند. API از چندین ورودی داده با رفتارهای متفاوت بر اساس محل انتقال داده پشتیبانی می کند. برنامه وب شما می تواند هنگام گوش دادن به رویدادهای ورودی، داده های منتقل شده را ارسال و دریافت کند.

این قابلیت می تواند طرز فکر ما را در مورد اشتراک گذاری و قابلیت همکاری در برنامه های وب روی دسکتاپ تغییر دهد. انتقال داده بین برنامه‌ها دیگر نیازی به اتکا به ادغام‌های محکم همراه ندارد. در عوض می توانید به کاربران کنترل کامل برای انتقال داده ها به هر کجا که دوست دارند بدهید.

نمونه ای از تعاملاتی که با DataTransfer API امکان پذیر است. (ویدئو شامل صدا نمی شود.)

انتقال داده

برای شروع، باید drag-drop یا copy-paste را پیاده سازی کنید. مثال‌های زیر تعاملات کشیدن و رها کردن را نشان می‌دهند، اما فرآیند کپی-پیست مشابه است. اگر با Drag and Drop 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 : وقتی در نوار 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);

انتقال با استفاده از کپی و پیست

استفاده از 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، می‌توانید با نوع عمومی Thing شروع کنید یا از چیزی نزدیک‌تر به مورد استفاده خود مانند Event ، Person ، MediaObject ، Place یا حتی انواع بسیار خاص مانند MedicalEntity در صورت نیاز استفاده کنید. هنگامی که از TypeScript استفاده می کنید، می توانید از تعاریف رابط از تعاریف نوع schema-dts استفاده کنید.

با انتقال و دریافت داده های JSON-LD، از یک وب متصل تر و بازتر پشتیبانی خواهید کرد. با برنامه هایی که به یک زبان صحبت می کنند، می توانید یکپارچگی عمیق با برنامه های خارجی ایجاد کنید. نیازی به ادغام های API پیچیده نیست. تمام اطلاعات مورد نیاز در داده های منتقل شده گنجانده شده است.

به همه امکانات برای انتقال داده بین هر برنامه (وب) بدون محدودیت فکر کنید: اشتراک گذاری رویدادها از یک تقویم به برنامه ToDo مورد علاقه خود، پیوست کردن فایل های مجازی به ایمیل ها، اشتراک گذاری مخاطبین. این عالی خواهد بود، درست است؟ این از شما شروع می شود! 🙌

نگرانی ها

در حالی که DataTransfer API امروزه در دسترس است، مواردی وجود دارد که قبل از ادغام باید از آنها آگاه بود.

سازگاری مرورگر

همه مرورگرهای دسکتاپ از تکنیکی که در بالا توضیح داده شد پشتیبانی عالی دارند، در حالی که دستگاه های تلفن همراه اینطور نیستند. این تکنیک بر روی تمامی مرورگرهای اصلی (Chrome، Edge، Firefox، Safari) و سیستم‌عامل‌ها (Android، ChromeOS، iOS، macOS، Ubuntu Linux و Windows) آزمایش شده است، اما متاسفانه اندروید و iOS این آزمون را قبول نکردند. در حالی که مرورگرها به توسعه خود ادامه می دهند، در حال حاضر این تکنیک فقط به مرورگرهای دسکتاپ محدود شده است.

قابلیت کشف

کشیدن و رها کردن و کپی پیست، تعاملات سطح سیستم هنگام کار بر روی یک رایانه رومیزی هستند که ریشه آن به اولین رابط کاربری گرافیکی بیش از 40 سال پیش بازمی گردد. به این فکر کنید که چند بار از این تعاملات برای سازماندهی فایل ها استفاده کرده اید. این هنوز در وب خیلی رایج نیست.

شما باید به کاربران در مورد این تعامل جدید آموزش دهید و الگوهای UX را برای قابل تشخیص کردن آن ارائه دهید، به خصوص برای افرادی که تجربه آنها با رایانه تا کنون به دستگاه های تلفن همراه محدود شده است.

قابلیت دسترسی

Drag-drop یک تعامل بسیار در دسترس نیست، اما DataTransfer API با کپی-پیست نیز کار می کند. مطمئن شوید که به رویدادهای کپی پیست گوش می دهید. کار اضافی زیادی نمی خواهد و کاربران شما بابت افزودن آن از شما سپاسگزار خواهند بود.

امنیت و حریم خصوصی

برخی ملاحظات امنیتی و حریم خصوصی وجود دارد که باید هنگام استفاده از این تکنیک از آنها آگاه باشید.

  • داده های کلیپ بورد برای سایر برنامه های کاربردی در دستگاه کاربر در دسترس است.
  • برنامه های وب که روی آنها می کشید به کلیدهای نوع دسترسی دارند، نه به داده ها. داده‌ها فقط در حالت drop یا paste در دسترس می‌شوند.
  • داده های دریافتی باید مانند هر ورودی دیگر کاربر رفتار شود. قبل از استفاده ضدعفونی و اعتبارسنجی شود.

شروع به کار با کتابخانه کمکی 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);

قدردانی ها

تصویر قهرمان توسط Luba Ertel در Unsplash .