تشرح هذه المشاركة أساسيات السحب والإفلات.
إنشاء محتوى قابل للسحب
في معظم المتصفحات، تكون تحديدات النصوص والصور والروابط قابلة للسحب بشكل تلقائي. على سبيل المثال، إذا سحبت رابطًا على صفحة ويب، سيظهر لك مربع صغير يحتوي على عنوان وعنوان URL يمكنك إفلاتهما في شريط العناوين أو على سطح المكتب لإنشاء اختصار أو الانتقال إلى الرابط. لجعل أنواع أخرى من المحتوى قابلة للسحب، عليك استخدام واجهات برمجة التطبيقات للسحب والإفلات في HTML5.
ولجعل أحد الكائنات قابلاً للسحب، عليك ضبط draggable=true
على ذلك العنصر. يمكن تفعيل ميزة السحب في أي عنصر تقريبًا، بما في ذلك الصور أو الملفات أو الروابط أو الملفات أو أي ترميز على صفحتك.
ينشئ المثال التالي واجهة لإعادة ترتيب الأعمدة التي
تم وضعها باستخدام شبكة CSS. يظهر الترميز الأساسي للأعمدة على هذا النحو،
مع ضبط السمة draggable
لكل عمود على true
:
<div class="container">
<div draggable="true" class="box">A</div>
<div draggable="true" class="box">B</div>
<div draggable="true" class="box">C</div>
</div>
في ما يلي لغة CSS لعناصر الحاوية والمربّع. خدمة CSS الوحيدة المرتبطة
بميزة السحب هي السمة cursor: move
. تتحكم باقي التعليمات البرمجية في تنسيق وتصميم عناصر الحاوية والمربع.
.container {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 10px;
}
.box {
border: 3px solid #666;
background-color: #ddd;
border-radius: .5em;
padding: 10px;
cursor: move;
}
في هذه المرحلة، يمكنك سحب العناصر، ولكن لن يحدث أي شيء آخر. لإضافة السلوك، عليك استخدام JavaScript API.
الاستماع إلى سحب الأحداث
لمراقبة عملية السحب، يمكنك الاستماع إلى أي من الأحداث التالية:
للتعامل مع تدفق السحب، تحتاج إلى نوع من العناصر المصدر (حيث يبدأ السحب)، وحمولة البيانات (الشيء الذي يتم سحبه)، وهدف (منطقة لالتقاط الانخفاض). يمكن أن يكون العنصر المصدر أي نوع من أنواع العناصر تقريبًا. الاستهداف هو منطقة الإفلات أو مجموعة مناطق الإفلات التي تقبل البيانات التي يحاول المستخدم إفلاتها. لا يمكن أن تكون كل العناصر أهدافًا. على سبيل المثال، لا يمكن أن يكون الهدف صورة.
بدء تسلسل سحب وإنهائه
بعد تحديد سمات draggable="true"
في المحتوى، أرفِق معالج أحداث dragstart
لبدء تسلسل السحب لكل عمود.
تعيّن هذه التعليمة البرمجية تعتيم العمود على 40٪ عندما يبدأ المستخدم في سحبه، ثم إعادته إلى 100٪ عند انتهاء حدث السحب.
function handleDragStart(e) {
this.style.opacity = '0.4';
}
function handleDragEnd(e) {
this.style.opacity = '1';
}
let items = document.querySelectorAll('.container .box');
items.forEach(function (item) {
item.addEventListener('dragstart', handleDragStart);
item.addEventListener('dragend', handleDragEnd);
});
يمكن الاطّلاع على النتيجة في الإصدار التجريبي التالي من Glitch. اسحب العنصر، ويتغير
درجة تعتيمه. بما أنّ العنصر المصدر يحتوي على حدث dragstart
، يؤدي ضبط
this.style.opacity
على% 40 إلى منح المستخدم ملاحظات مرئية بأنّ هذا العنصر
هو العنصر المحدّد الذي يتم نقله حاليًا. عند إسقاط العنصر، يعود العنصر المصدر
إلى معدل شفافية 100%، على الرغم من أنك لم تحدد سلوك الانخفاض بعد.
إضافة رموز مرئية إضافية
لمساعدة المستخدم في فهم كيفية التفاعل مع واجهتك، استخدِم
معالِجات الأحداث dragenter
وdragover
وdragleave
. في هذا المثال، الأعمدة هي
أهداف إسقاط بالإضافة إلى كونها قابلة للسحب. ساعد المستخدم على فهم ذلك عن طريق جعل الحد متقطع عندما يمسك عنصرًا تم سحبه فوق عمود. على سبيل المثال، في CSS، يمكنك إنشاء فئة over
للعناصر التي لا تمثّل أهدافًا:
.box.over {
border: 3px dotted #666;
}
بعد ذلك، في JavaScript، اضبط معالِجات الأحداث، وأضِف الفئة over
عند سحب العمود، وأزِلها عند مغادرة العنصر المسحوب. في معالج dragend
، نتأكد أيضًا من إزالة الفئات في نهاية السحب.
document.addEventListener('DOMContentLoaded', (event) => {
function handleDragStart(e) {
this.style.opacity = '0.4';
}
function handleDragEnd(e) {
this.style.opacity = '1';
items.forEach(function (item) {
item.classList.remove('over');
});
}
function handleDragOver(e) {
e.preventDefault();
return false;
}
function handleDragEnter(e) {
this.classList.add('over');
}
function handleDragLeave(e) {
this.classList.remove('over');
}
let items = document.querySelectorAll('.container .box');
items.forEach(function(item) {
item.addEventListener('dragstart', handleDragStart);
item.addEventListener('dragover', handleDragOver);
item.addEventListener('dragenter', handleDragEnter);
item.addEventListener('dragleave', handleDragLeave);
item.addEventListener('dragend', handleDragEnd);
item.addEventListener('drop', handleDrop);
});
});
هناك نقطتين تستحق تناولهما في هذا الرمز:
الإجراء التلقائي لحدث
dragover
هو ضبط السمةdataTransfer.dropEffect
على"none"
. ويتم تناول السمةdropEffect
لاحقًا في هذه الصفحة. في الوقت الحالي، ما عليك سوى معرفة أنّ هذا الإجراء يمنع تنشيط حدثdrop
. لتجاوز هذا السلوك، اتصل بـe.preventDefault()
. ومن الممارسات الجيدة الأخرى عرضfalse
في المعالج نفسه.يُستخدَم معالج الحدث
dragenter
لتبديل الفئةover
بدلاً منdragover
. في حال استخدام السمةdragover
، يتم تنشيط الحدث بشكل متكرّر أثناء حمل المستخدم للعنصر المسحوب فوق أحد الأعمدة، ما يؤدي إلى تبديل فئة CSS بشكل متكرّر. فهذا يجعل المتصفح يجري الكثير من أعمال العرض غير الضرورية، مما قد يؤثر على تجربة المستخدم. ننصحك بشدة بتقليل عمليات إعادة الرسم، وإذا كنت بحاجة إلى استخدامdragover
، ننصحك بتقييد أو إلغاء ارتداد أداة معالجة الحدث.
إكمال عملية الطرح
لمعالجة الانخفاض المفاجئ، أضِف أداة معالجة للحدث إلى حدث drop
. في معالج drop
، عليك منع السلوك التلقائي للمتصفح مع الإفلات، والذي يكون عادةً نوعًا من عمليات إعادة التوجيه المزعجة. لإجراء ذلك، يُرجى الاتصال بـ "e.stopPropagation()
".
function handleDrop(e) {
e.stopPropagation(); // stops the browser from redirecting.
return false;
}
تأكد من تسجيل المعالج الجديد إلى جانب المعالجات الأخرى:
let items = document.querySelectorAll('.container .box');
items.forEach(function(item) {
item.addEventListener('dragstart', handleDragStart);
item.addEventListener('dragover', handleDragOver);
item.addEventListener('dragenter', handleDragEnter);
item.addEventListener('dragleave', handleDragLeave);
item.addEventListener('dragend', handleDragEnd);
item.addEventListener('drop', handleDrop);
});
إذا قمت بتشغيل الرمز في هذه المرحلة، لن يتم إسقاط العنصر في الموقع الجديد. ولتحقيق ذلك، استخدِم الكائن DataTransfer
.
تحتفظ السمة dataTransfer
بالبيانات المُرسَلة عبر إجراء سحب. يتم ضبط dataTransfer
في حدث dragstart
وتتم قراءته أو التعامل معه في حدث الإفلات. يتيح لك طلب البيانات
e.dataTransfer.setData(mimeType, dataPayload)
ضبط نوع MIME للكائن وحمولة البيانات.
في هذا المثال، سنسمح للمستخدمين بإعادة ترتيب ترتيب الأعمدة. للقيام بذلك، تحتاج أولاً إلى تخزين HTML للعنصر المصدر عند بدء السحب:
function handleDragStart(e) {
this.style.opacity = '0.4';
dragSrcEl = this;
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/html', this.innerHTML);
}
في حدث drop
، عليك معالجة انخفاض العمود من خلال ضبط رمز HTML لعمود المصدر
على HTML الخاص بالعمود المستهدَف الذي نقلت البيانات إليه. يتضمن ذلك التحقق من أن المستخدم لا يعود إلى نفس العمود الذي قام بسحبه.
function handleDrop(e) {
e.stopPropagation();
if (dragSrcEl !== this) {
dragSrcEl.innerHTML = this.innerHTML;
this.innerHTML = e.dataTransfer.getData('text/html');
}
return false;
}
ويمكنك الاطّلاع على النتيجة في العرض التوضيحي التالي. لكي تنجح هذه الطريقة، ستحتاج إلى متصفّح متوافق مع أجهزة الكمبيوتر المكتبي. لا تتوفر واجهة برمجة التطبيقات "السحب والإفلات" على الأجهزة الجوّالة. اسحب وأصدر العمود A أعلى العمود B ولاحظ كيف تغير الأماكن:
المزيد من خصائص السحب
يعرض الكائن dataTransfer
الخصائص لتقديم ملاحظات مرئية للمستخدم أثناء عملية السحب والتحكم في كيفية استجابة كل هدف إفلات لنوع بيانات معيّن.
dataTransfer.effectAllowed
يقيد "نوع السحب" الذي يمكن للمستخدم تنفيذه على العنصر. وتُستخدَم في نموذج معالجة السحب والإفلات لإعدادdropEffect
أثناء حدثَيdragenter
وdragover
. ويمكن أن تحتوي السمة على القيم التالية:none
وcopy
وcopyLink
وcopyMove
وlink
وlinkMove
وmove
وall
وuninitialized
.- تتحكّم
dataTransfer.dropEffect
في الملاحظات التي يتلقّاها المستخدم خلال حدثَيdragenter
وdragover
. عندما يرفع المستخدم مؤشر الماوس فوق عنصر هدف، يشير مؤشر المتصفح إلى نوع العملية التي سيتم تنفيذها، مثل عملية نسخ أو نقل. ويمكن أن يستخدم التأثير إحدى القيم التالية:none
أوcopy
أوlink
أوmove
. - تعني العلامة
e.dataTransfer.setDragImage(imgElement, x, y)
أنّه يمكنك ضبط رمز السحب بدلاً من استخدام تعليقات "الصورة المفرغة" التلقائية في المتصفّح.
تحميل ملف
يستخدم هذا المثال البسيط عمودًا كمصدر للسحب وهدف السحب. قد يحدث هذا في واجهة المستخدم التي تطلب من المستخدم إعادة ترتيب العناصر. في بعض الحالات، قد يكون هدف السحب والمصدر نوعين مختلفين من العناصر، كما هو الحال في الواجهة حيث يحتاج المستخدم إلى تحديد صورة واحدة كصورة رئيسية للمنتج عن طريق سحب الصورة المحددة إلى الهدف.
يتم استخدام السحب والإفلات بشكل متكرر للسماح للمستخدمين بسحب العناصر من سطح المكتب إلى
أحد التطبيقات. الاختلاف الرئيسي هو في معالج drop
. بدلاً من استخدام
"dataTransfer.getData()
" للوصول إلى الملفات، يتم تضمين بيانات هذه الملفات في السمة
dataTransfer.files
:
function handleDrop(e) {
e.stopPropagation(); // Stops some browsers from redirecting.
e.preventDefault();
var files = e.dataTransfer.files;
for (var i = 0, f; (f = files[i]); i++) {
// Read the File objects in this FileList.
}
}
يمكنك العثور على مزيد من المعلومات حول هذا الموضوع من خلال السحب والإفلات المخصّص.