You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/translations/ar/3-terrarium/3-intro-to-DOM-and-closures
softchris 04881ec984
🌐 Update translations via Co-op Translator
10 months ago
..
README.md 🌐 Update translations via Co-op Translator 10 months ago
assignment.md 🌐 Update translations via Co-op Translator 12 months ago

README.md

مشروع التيراريوم الجزء الثالث: التلاعب بـ DOM والإغلاق

DOM والإغلاق

رسم توضيحي بواسطة Tomomi Imura

اختبار ما قبل المحاضرة

اختبار ما قبل المحاضرة

المقدمة

التلاعب بـ DOM، أو "نموذج كائن المستند"، هو جانب أساسي من تطوير الويب. وفقًا لـ MDN، "نموذج كائن المستند (DOM) هو تمثيل البيانات للكائنات التي تشكل هيكل ومحتوى مستند على الويب." التحديات المتعلقة بالتلاعب بـ DOM على الويب غالبًا ما كانت الدافع وراء استخدام أطر عمل JavaScript بدلاً من JavaScript العادي لإدارة DOM، ولكننا سنتعامل مع الأمر بأنفسنا!

بالإضافة إلى ذلك، ستقدم هذه الدرس فكرة الإغلاق في JavaScript، والتي يمكنك التفكير فيها كوظيفة مغلقة بواسطة وظيفة أخرى بحيث يكون للوظيفة الداخلية الوصول إلى نطاق الوظيفة الخارجية.

الإغلاقات في JavaScript موضوع واسع ومعقد. يتناول هذا الدرس الفكرة الأساسية فقط وهي أنه في كود التيراريوم، ستجد إغلاقًا: وظيفة داخلية ووظيفة خارجية تم إنشاؤها بطريقة تسمح للوظيفة الداخلية بالوصول إلى نطاق الوظيفة الخارجية. للحصول على معلومات أكثر تفصيلًا حول كيفية عمل ذلك، يرجى زيارة الوثائق الشاملة.

سنستخدم الإغلاق للتلاعب بـ DOM.

فكر في DOM كشجرة تمثل جميع الطرق التي يمكن من خلالها التلاعب بمستند صفحة الويب. تم كتابة واجهات برمجية مختلفة (APIs) بحيث يمكن للمبرمجين، باستخدام لغة البرمجة التي يختارونها، الوصول إلى DOM وتحريره وتغييره وإعادة ترتيبه وإدارته بطرق أخرى.

تمثيل شجرة DOM

تمثيل لـ DOM وعلامات HTML التي تشير إليه. من Olfa Nasraoui

في هذا الدرس، سنكمل مشروع التيراريوم التفاعلي الخاص بنا عن طريق إنشاء JavaScript الذي سيسمح للمستخدم بالتلاعب بالنباتات على الصفحة.

المتطلبات الأساسية

يجب أن تكون قد أنشأت HTML وCSS للتيراريوم الخاص بك. بحلول نهاية هذا الدرس، ستتمكن من نقل النباتات إلى داخل وخارج التيراريوم عن طريق سحبها.

المهمة

في مجلد التيراريوم الخاص بك، قم بإنشاء ملف جديد يسمى script.js. قم باستيراد هذا الملف في قسم <head>:

	<script src="./script.js" defer></script>

ملاحظة: استخدم defer عند استيراد ملف JavaScript خارجي إلى ملف HTML للسماح بتنفيذ JavaScript فقط بعد تحميل ملف HTML بالكامل. يمكنك أيضًا استخدام خاصية async، التي تسمح بتنفيذ السكربت أثناء تحليل ملف HTML، ولكن في حالتنا، من المهم أن تكون عناصر HTML متاحة بالكامل للسحب قبل تنفيذ سكربت السحب.


عناصر DOM

أول شيء تحتاج إلى القيام به هو إنشاء مراجع للعناصر التي تريد التلاعب بها في DOM. في حالتنا، هي الـ 14 نباتًا الموجودة حاليًا في الجوانب.

المهمة

dragElement(document.getElementById('plant1'));
dragElement(document.getElementById('plant2'));
dragElement(document.getElementById('plant3'));
dragElement(document.getElementById('plant4'));
dragElement(document.getElementById('plant5'));
dragElement(document.getElementById('plant6'));
dragElement(document.getElementById('plant7'));
dragElement(document.getElementById('plant8'));
dragElement(document.getElementById('plant9'));
dragElement(document.getElementById('plant10'));
dragElement(document.getElementById('plant11'));
dragElement(document.getElementById('plant12'));
dragElement(document.getElementById('plant13'));
dragElement(document.getElementById('plant14'));

ما الذي يحدث هنا؟ أنت تشير إلى المستند وتبحث في DOM الخاص به للعثور على عنصر بمعرف معين. تذكر في الدرس الأول عن HTML أنك أعطيت معرفات فردية لكل صورة نبات (id="plant1"). الآن ستستفيد من هذا الجهد. بعد تحديد كل عنصر، تقوم بتمرير هذا العنصر إلى وظيفة تسمى dragElement التي ستقوم ببنائها قريبًا. وبالتالي، العنصر في HTML أصبح جاهزًا للسحب، أو سيكون كذلك قريبًا.

لماذا نشير إلى العناصر بواسطة المعرف؟ لماذا لا نستخدم الفئة الخاصة بـ CSS؟ قد تعود إلى الدرس السابق عن CSS للإجابة على هذا السؤال.


الإغلاق

الآن أنت جاهز لإنشاء إغلاق dragElement، وهو وظيفة خارجية تغلق وظيفة داخلية أو وظائف (في حالتنا، سيكون لدينا ثلاث وظائف).

الإغلاقات مفيدة عندما تحتاج وظيفة أو أكثر إلى الوصول إلى نطاق الوظيفة الخارجية. إليك مثال:

function displayCandy(){
	let candy = ['jellybeans'];
	function addCandy(candyType) {
		candy.push(candyType)
	}
	addCandy('gumdrops');
}
displayCandy();
console.log(candy)

في هذا المثال، تحيط وظيفة displayCandy بوظيفة تضيف نوعًا جديدًا من الحلوى إلى مصفوفة موجودة بالفعل في الوظيفة. إذا قمت بتشغيل هذا الكود، ستكون المصفوفة candy غير معرفة، لأنها متغير محلي (محلي لنطاق الإغلاق).

كيف يمكنك جعل المصفوفة candy قابلة للوصول؟ حاول نقلها خارج الإغلاق. بهذه الطريقة، تصبح المصفوفة عالمية، بدلاً من أن تظل متاحة فقط لنطاق الإغلاق المحلي.

المهمة

تحت تعريف العناصر في script.js، قم بإنشاء وظيفة:

function dragElement(terrariumElement) {
	//set 4 positions for positioning on the screen
	let pos1 = 0,
		pos2 = 0,
		pos3 = 0,
		pos4 = 0;
	terrariumElement.onpointerdown = pointerDrag;
}

dragElement يحصل على كائن terrariumElement الخاص به من التعريفات في أعلى السكربت. ثم تقوم بتعيين بعض المواضع المحلية عند 0 للكائن الممرر إلى الوظيفة. هذه هي المتغيرات المحلية التي سيتم التلاعب بها لكل عنصر أثناء إضافة وظيفة السحب والإفلات داخل الإغلاق لكل عنصر. سيتم ملء التيراريوم بهذه العناصر المسحوبة، لذا يحتاج التطبيق إلى تتبع مكان وضعها.

بالإضافة إلى ذلك، يتم تعيين terrariumElement الذي يتم تمريره إلى هذه الوظيفة حدث pointerdown، وهو جزء من واجهات برمجية للويب المصممة للمساعدة في إدارة DOM. يتم تشغيل onpointerdown عندما يتم الضغط على زر، أو في حالتنا، يتم لمس عنصر قابل للسحب. يعمل هذا المعالج للأحداث على كل من متصفحات الويب والجوال، مع بعض الاستثناءات.

معالج الأحداث onclick لديه دعم أكبر عبر المتصفحات؛ لماذا لا تستخدمه هنا؟ فكر في نوع التفاعل الدقيق الذي تحاول إنشاؤه هنا.


وظيفة Pointerdrag

العنصر terrariumElement جاهز للسحب؛ عندما يتم تشغيل حدث onpointerdown، يتم استدعاء وظيفة pointerDrag. أضف تلك الوظيفة مباشرة تحت هذا السطر: terrariumElement.onpointerdown = pointerDrag;:

المهمة

function pointerDrag(e) {
	e.preventDefault();
	console.log(e);
	pos3 = e.clientX;
	pos4 = e.clientY;
}

تحدث عدة أمور. أولاً، تمنع الأحداث الافتراضية التي تحدث عادةً عند pointerdown من الحدوث باستخدام e.preventDefault();. بهذه الطريقة لديك المزيد من التحكم في سلوك الواجهة.

عد إلى هذا السطر عندما تكون قد أنشأت ملف السكربت بالكامل وجربه بدون e.preventDefault() - ماذا يحدث؟

ثانيًا، افتح index.html في نافذة المتصفح، وقم بفحص الواجهة. عندما تنقر على نبات، يمكنك رؤية كيف يتم التقاط حدث 'e'. استكشف الحدث لترى مقدار المعلومات التي يتم جمعها بواسطة حدث pointerdown واحد!

بعد ذلك، لاحظ كيف يتم تعيين المتغيرات المحلية pos3 و pos4 إلى e.clientX. يمكنك العثور على قيم e في نافذة الفحص. هذه القيم تلتقط إحداثيات x و y للنبات في اللحظة التي تنقر عليه أو تلمسه. ستحتاج إلى تحكم دقيق في سلوك النباتات أثناء النقر عليها وسحبها، لذا تحتفظ بإحداثياتها.

هل أصبح من الواضح أكثر لماذا يتم بناء هذا التطبيق بالكامل باستخدام إغلاق كبير؟ إذا لم يكن كذلك، كيف ستحتفظ بالنطاق لكل من النباتات الـ 14 القابلة للسحب؟

أكمل الوظيفة الأولية بإضافة عمليتي تلاعب إضافيتين بأحداث المؤشر تحت pos4 = e.clientY:

document.onpointermove = elementDrag;
document.onpointerup = stopElementDrag;

الآن تشير إلى أنك تريد أن يتم سحب النبات مع المؤشر أثناء تحريكه، ولإيقاف حركة السحب عند إلغاء تحديد النبات. onpointermove و onpointerup هما جزء من نفس الواجهة البرمجية مثل onpointerdown. ستقوم الواجهة الآن بإلقاء أخطاء لأنك لم تقم بعد بتعريف وظائف elementDrag و stopElementDrag، لذا قم ببنائها بعد ذلك.

وظائف elementDrag و stopElementDrag

ستكمل الإغلاق الخاص بك بإضافة وظيفتين داخليتين إضافيتين ستتعاملان مع ما يحدث عند سحب النبات وإيقاف سحبه. السلوك الذي تريده هو أن تتمكن من سحب أي نبات في أي وقت ووضعه في أي مكان على الشاشة. هذه الواجهة غير مقيدة تمامًا (لا توجد منطقة إسقاط على سبيل المثال) للسماح لك بتصميم التيراريوم الخاص بك بالطريقة التي تريدها عن طريق إضافة وإزالة وإعادة وضع النباتات.

المهمة

أضف وظيفة elementDrag مباشرة بعد القوس المغلق لـ pointerDrag:

function elementDrag(e) {
	pos1 = pos3 - e.clientX;
	pos2 = pos4 - e.clientY;
	pos3 = e.clientX;
	pos4 = e.clientY;
	console.log(pos1, pos2, pos3, pos4);
	terrariumElement.style.top = terrariumElement.offsetTop - pos2 + 'px';
	terrariumElement.style.left = terrariumElement.offsetLeft - pos1 + 'px';
}

في هذه الوظيفة، تقوم بالكثير من تحرير المواضع الأولية 1-4 التي قمت بتعيينها كمتغيرات محلية في الوظيفة الخارجية. ما الذي يحدث هنا؟

أثناء السحب، تعيد تعيين pos1 بجعلها مساوية لـ pos3 (التي قمت بتعيينها سابقًا كـ e.clientX) ناقص القيمة الحالية لـ e.clientX. تقوم بعملية مشابهة لـ pos2. ثم تعيد تعيين pos3 و pos4 إلى إحداثيات X و Y الجديدة للعنصر. يمكنك مشاهدة هذه التغييرات في وحدة التحكم أثناء السحب. ثم تقوم بتعديل نمط CSS للنبات لتعيين موضعه الجديد بناءً على المواضع الجديدة لـ pos1 و pos2، مع حساب إحداثيات X و Y العلوية واليسرى للنبات بناءً على مقارنة إزاحته مع هذه المواضع الجديدة.

offsetTop و offsetLeft هما خصائص CSS تحدد موضع العنصر بناءً على موضع العنصر الأب؛ يمكن أن يكون العنصر الأب أي عنصر ليس موضعه static.

كل هذه العمليات الحسابية لإعادة تحديد المواضع تتيح لك ضبط سلوك التيراريوم ونباتاته بدقة.

المهمة

المهمة النهائية لإكمال الواجهة هي إضافة وظيفة stopElementDrag بعد القوس المغلق لـ elementDrag:

function stopElementDrag() {
	document.onpointerup = null;
	document.onpointermove = null;
}

هذه الوظيفة الصغيرة تعيد تعيين أحداث onpointerup و onpointermove بحيث يمكنك إما إعادة بدء تقدم النبات عن طريق البدء في سحبه مرة أخرى، أو بدء سحب نبات جديد.

ماذا يحدث إذا لم تقم بتعيين هذه الأحداث إلى null؟

الآن لقد أكملت مشروعك!

🥇تهانينا! لقد أنهيت تيراريومك الجميل. التيراريوم النهائي


تحدي وكيل GitHub Copilot 🚀

استخدم وضع الوكيل لإكمال التحدي التالي:

الوصف: قم بتحسين مشروع التيراريوم عن طريق إضافة وظيفة إعادة تعيين تعيد جميع النباتات إلى مواقعها الأصلية مع تأثيرات حركة سلسة.

المهمة: قم بإنشاء زر إعادة تعيين، وعندما يتم النقر عليه، يعيد جميع النباتات إلى مواقعها الأصلية في الجوانب مع انتقالات سلسة باستخدام CSS. يجب أن تخزن الوظيفة المواقع الأصلية عند تحميل الصفحة وتعيد النباتات بسلاسة إلى تلك المواقع خلال ثانية واحدة عند الضغط على زر إعادة التعيين.

🚀التحدي

أضف معالج أحداث جديد إلى الإغلاق الخاص بك للقيام بشيء إضافي للنباتات؛ على سبيل المثال، انقر نقرًا مزدوجًا على النبات لجعله يظهر في المقدمة. كن مبدعًا!

اختبار ما بعد المحاضرة

اختبار ما بعد المحاضرة

المراجعة والدراسة الذاتية

على الرغم من أن سحب العناصر حول الشاشة يبدو أمرًا بسيطًا، إلا أن هناك العديد من الطرق للقيام بذلك والعديد من العقبات، اعتمادًا على التأثير الذي تسعى إليه. في الواقع، هناك واجهة برمجية للسحب والإفلات يمكنك تجربتها. لم نستخدمها في هذه الوحدة لأن التأثير الذي أردناه كان مختلفًا بعض الشيء، ولكن جرب هذه الواجهة البرمجية في مشروعك الخاص وشاهد ما يمكنك تحقيقه.

ابحث عن المزيد من المعلومات حول أحداث المؤشر في وثائق W3C وعلى وثائق MDN للويب.

تحقق دائمًا من قدرات المتصفح باستخدام CanIUse.com.

الواجب

اعمل قليلاً مع DOM


إخلاء المسؤولية:
تم ترجمة هذا المستند باستخدام خدمة الترجمة بالذكاء الاصطناعي Co-op Translator. بينما نسعى لتحقيق الدقة، يرجى العلم أن الترجمات الآلية قد تحتوي على أخطاء أو عدم دقة. يجب اعتبار المستند الأصلي بلغته الأصلية المصدر الرسمي. للحصول على معلومات حاسمة، يُوصى بالترجمة البشرية الاحترافية. نحن غير مسؤولين عن أي سوء فهم أو تفسيرات خاطئة تنشأ عن استخدام هذه الترجمة.