فعِّل للمستخدم مشاركة البيانات خارج نافذة المتصفّح.
ربما سمعت عن DataTransfer API، وهي جزء من HTML5 Drag and Drop API وأحداث الحافظة. ويمكن استخدامه لنقل البيانات بين المصدر والأهداف المستلِمة.
غالبًا ما يتم استخدام تفاعلات السحب والإفلات والنسخ واللصق للتفاعلات داخل الصفحة لنقل نص بسيط من "أ" إلى "ب". ولكن ما يتم تجاهله في كثير من الأحيان هو إمكانية استخدام هذه التفاعلات نفسها للوصول إلى ما هو أبعد من نافذة المتصفّح.
يمكن أن تتواصل تفاعلات السحب والإفلات المضمّنة في المتصفّح وعمليات النسخ واللصق مع التطبيقات الأخرى أو الويب أو غير ذلك، وهي ليست مرتبطة بأي مصدر. تتيح واجهة برمجة التطبيقات إدخالات بيانات متعددة بسلوكيات مختلفة استنادًا إلى المكان الذي يتم نقل البيانات إليه. يمكن لتطبيق الويب إرسال البيانات المنقولة واستلامها عند الاستماع إلى الأحداث الواردة.
يمكن أن تغيّر هذه الميزة طريقة تفكيرنا في المشاركة والتشغيل التفاعلي في تطبيقات الويب على أجهزة الكمبيوتر المكتبي. لم يعُد نقل البيانات بين التطبيقات يعتمد على عمليات دمج مرتبطة ببعضها بشكل وثيق. بدلاً من ذلك، يمكنك منح المستخدمين إمكانية التحكّم الكامل في نقل data إلى أي مكان يرونه مناسبًا.
نقل البيانات
للبدء، عليك استخدام ميزة السحب والإفلات أو النسخ واللصق. تعرض الأمثلة التالية إجراءات التفاعل من خلال السحب والإفلات، ولكن عملية النسخ واللصق مشابهة. إذا لم تكن على دراية بواجهة برمجة التطبيقات Drag and Drop API، يمكنك الاطّلاع على مقالة رائعة توضّح ميزة HTML5 Drag and Drop.
من خلال تقديم بيانات مفتاح MIME-type، يمكنك التفاعل بحرية مع التطبيقات الخارجية. تستجيب معظم محرّرات 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" وMicrosoft Word وغيرها. text/plain:
لضبط قيمة عناصر الإدخال ومحتوى محرّري الرموز البرمجية والعنصر الاحتياطي منtext/html
text/uri-list
: الانتقال إلى عنوان URL عند إسقاطه على شريط عنوان URL أو صفحة المتصفّح سيتم إنشاء اختصار لعنوان URL عند إسقاطه في دليل أو على سطح المكتب.
إنّ استخدام محرّري WYSIWYG لرمز text/html
على نطاق واسع يجعله مفيدًا جدًا. كما هو الحال في مستندات HTML، يمكنك تضمين الموارد باستخدام عناوين URL للبيانات أو عناوين URL متاحة للجميع. يعمل ذلك بشكل جيد مع تصدير العناصر المرئية (على سبيل المثال من لوحة) إلى محرّرات مثل "مستندات Google".
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 واستلامها، ستساهم في توفير ويب أكثر اتّصالاً وانفتاحًا. باستخدام التطبيقات التي تستخدم اللغة نفسها، يمكنك إنشاء عمليات دمج وثيقة مع التطبيقات الخارجية. ما مِن حاجة إلى عمليات دمج معقدة لواجهات برمجة التطبيقات، فجميع المعلومات المطلوبة مضمّنة في البيانات المنقولة.
فكِّر في جميع الاحتمالات لنقل البيانات بين أي تطبيق (على الويب) بدون قيود: مشاركة الأحداث من تقويم إلى تطبيق المهام المفضّل لديك، وإرفاق ملفات افتراضية برسائل البريد الإلكتروني، ومشاركة جهات الاتصال. سيكون ذلك رائعًا، أليس كذلك؟ يبدأ ذلك منك. 🙌
المخاوف والمشاكل الطبية
على الرغم من توفّر DataTransfer API حاليًا، هناك بعض الأمور التي يجب أخذها في الاعتبار قبل الدمج.
توافُق المتصفح
تتوافق جميع متصفّحات أجهزة الكمبيوتر المكتبي بشكلٍ رائع مع التقنية الموضّحة أعلاه، في حين لا تتوافق الأجهزة الجوّالة معها. تم اختبار هذه الطريقة على جميع المتصفحات الرئيسية (Chrome وEdge وFirefox وSafari) و أنظمة التشغيل (Android وChromeOS وiOS وmacOS وUbuntu Linux وWindows)، ولكن للأسف لم يجتاز Android وiOS الاختبار. مع استمرار تطوير المتصفّحات، تقتصر هذه التقنية في الوقت الحالي على متصفّحات أجهزة الكمبيوتر المكتبي فقط.
سهولة العثور على المحتوى
إنّ ميزة السحب والإفلات وميزة النسخ واللصق هما تفاعلان على مستوى النظام عند العمل على كمبيوتر مكتبي، ويعودان أصولهما إلى واجهة المستخدم الرسومية الأولى التي تم إنشاؤها قبل أكثر من 40 عامًا. فكِّر في عدد المرات التي استخدمت فيها هذه التفاعلات لتنظيم الملفات. ولا تزال هذه الميزة غير شائعة على الويب.
عليك إبلاغ المستخدمين بهذا التفاعل الجديد، وإنشاء أنماط لتجربة المستخدم لكي يتم التعرّف عليه، خاصةً للأشخاص الذين اقتصرت تجربتهم مع أجهزة الكمبيوتر حتى الآن على الأجهزة الجوّالة.
تسهيل الاستخدام
لا يُعدّ سحب العناصر وإفلاتها تفاعلاً سهل الاستخدام، ولكن تعمل واجهة برمجة التطبيقات DataTransfer API مع ميزة النسخ واللصق أيضًا. تأكَّد من رصد أحداث النسخ واللصق. لا يستغرق ذلك الكثير من الجهد الإضافي، وسيقدّر المستخدمون إضافة هذه الميزة.
الأمان والخصوصية
هناك بعض الاعتبارات المتعلقة بالأمان والخصوصية التي يجب أخذها في الاعتبار عند استخدام هذه الطريقة.
- تتوفّر بيانات الحافظة للتطبيقات الأخرى على جهاز المستخدم.
- يمكن لتطبيقات الويب التي تسحبها الوصول إلى مفاتيح النوع، وليس البيانات. لا تصبح البيانات متاحة إلا عند إسقاطها أو لصقها.
- يجب التعامل مع البيانات المستلَمة كما هو الحال مع أي إدخال آخر من المستخدم، أي يجب تطهيرها والتحقّق من صحتها قبل استخدامها.
بدء استخدام مكتبة 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);
الشكر والتقدير
الصورة الرئيسية تقدّمها لوبا إيرتل على Unsplash.