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/fa/3-terrarium/3-intro-to-DOM-and-closures
leestott 7cfaffabb5
🌐 Update translations via Co-op Translator
3 weeks ago
..
README.md 🌐 Update translations via Co-op Translator 3 weeks ago
assignment.md 🌐 Update translations via Co-op Translator 4 weeks ago

README.md

پروژه تراریوم بخش ۳: دستکاری DOM و Closure

DOM و Closure

طراحی توسط Tomomi Imura

آزمون پیش از درس

آزمون پیش از درس

مقدمه

دستکاری DOM، یا "مدل شیء سند"، یکی از جنبه‌های کلیدی توسعه وب است. طبق گفته MDN، "مدل شیء سند (DOM) نمایش داده‌ای از اشیایی است که ساختار و محتوای یک سند در وب را تشکیل می‌دهند." چالش‌های مربوط به دستکاری DOM در وب اغلب انگیزه‌ای برای استفاده از فریم‌ورک‌های جاوااسکریپت به جای جاوااسکریپت خالص برای مدیریت DOM بوده است، اما ما خودمان این کار را انجام خواهیم داد!

علاوه بر این، این درس ایده Closure در جاوااسکریپت را معرفی می‌کند، که می‌توانید آن را به عنوان یک تابع درون تابع دیگری تصور کنید، به طوری که تابع داخلی به محدوده تابع خارجی دسترسی دارد.

Closure در جاوااسکریپت موضوعی گسترده و پیچیده است. این درس به ساده‌ترین ایده می‌پردازد که در کد این تراریوم، یک Closure وجود دارد: یک تابع داخلی و یک تابع خارجی که به گونه‌ای ساخته شده‌اند که تابع داخلی به محدوده تابع خارجی دسترسی داشته باشد. برای اطلاعات بیشتر در مورد نحوه عملکرد این موضوع، لطفاً به مستندات جامع مراجعه کنید.

ما از یک Closure برای دستکاری DOM استفاده خواهیم کرد.

DOM را به عنوان یک درخت تصور کنید که تمام روش‌هایی را که یک سند صفحه وب می‌تواند دستکاری شود، نشان می‌دهد. APIهای مختلفی (رابط‌های برنامه‌نویسی کاربردی) نوشته شده‌اند تا برنامه‌نویسان بتوانند با استفاده از زبان برنامه‌نویسی مورد نظر خود به DOM دسترسی پیدا کرده و آن را ویرایش، تغییر، بازآرایی و مدیریت کنند.

نمایش درخت DOM

نمایشی از DOM و کد HTML که به آن اشاره دارد. از Olfa Nasraoui

در این درس، پروژه تعاملی تراریوم خود را با ایجاد جاوااسکریپتی که به کاربر اجازه می‌دهد گیاهان را در صفحه جابه‌جا کند، تکمیل خواهیم کرد.

پیش‌نیاز

شما باید HTML و CSS تراریوم خود را ساخته باشید. تا پایان این درس، قادر خواهید بود گیاهان را با کشیدن و رها کردن به داخل و خارج تراریوم منتقل کنید.

وظیفه

در پوشه تراریوم خود، یک فایل جدید به نام script.js ایجاد کنید. این فایل را در بخش <head> وارد کنید:

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

توجه: هنگام وارد کردن یک فایل جاوااسکریپت خارجی به فایل HTML، از defer استفاده کنید تا جاوااسکریپت فقط پس از بارگذاری کامل فایل HTML اجرا شود. همچنین می‌توانید از ویژگی async استفاده کنید که به اسکریپت اجازه می‌دهد در حین تجزیه فایل HTML اجرا شود، اما در مورد ما، مهم است که عناصر HTML قبل از اجرای اسکریپت کشیدن کاملاً در دسترس باشند.


عناصر DOM

اولین کاری که باید انجام دهید این است که به عناصری که می‌خواهید در DOM دستکاری کنید، ارجاع دهید. در مورد ما، این عناصر ۱۴ گیاهی هستند که در حال حاضر در نوارهای کناری قرار دارند.

وظیفه

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 آن به دنبال عنصری با یک Id خاص می‌گردید. به یاد دارید که در اولین درس HTML به هر تصویر گیاه یک Id جداگانه دادید (id="plant1")؟ اکنون از آن تلاش استفاده خواهید کرد. پس از شناسایی هر عنصر، آن مورد را به تابعی به نام dragElement که در یک لحظه خواهید ساخت، ارسال می‌کنید. بنابراین، عنصر در HTML اکنون قابلیت کشیدن دارد، یا به زودی خواهد داشت.

چرا عناصر را با Id ارجاع می‌دهیم؟ چرا نه با کلاس CSS؟ ممکن است به درس قبلی در مورد CSS مراجعه کنید تا به این سؤال پاسخ دهید.


Closure

اکنون آماده ایجاد Closure dragElement هستید، که یک تابع خارجی است که یک یا چند تابع داخلی را در بر می‌گیرد (در مورد ما، سه تابع خواهیم داشت).

Closure زمانی مفید است که یک یا چند تابع نیاز به دسترسی به محدوده تابع خارجی داشته باشند. در اینجا یک مثال آورده شده است:

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

در این مثال، تابع displayCandy تابعی را در بر می‌گیرد که یک نوع آب‌نبات جدید را به آرایه‌ای که قبلاً در تابع وجود دارد، اضافه می‌کند. اگر این کد را اجرا کنید، آرایه candy تعریف نشده خواهد بود، زیرا یک متغیر محلی است (محلی برای Closure).

چگونه می‌توانید آرایه candy را در دسترس قرار دهید؟ سعی کنید آن را خارج از Closure منتقل کنید. به این ترتیب، آرایه به جای اینکه فقط در محدوده محلی Closure در دسترس باشد، جهانی می‌شود.

وظیفه

زیر اعلان عناصر در 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 تنظیم می‌کنید. این‌ها متغیرهای محلی هستند که برای هر عنصر هنگام افزودن قابلیت کشیدن و رها کردن در Closure دستکاری خواهند شد. تراریوم با این عناصر کشیده شده پر خواهد شد، بنابراین برنامه باید مکان آن‌ها را پیگیری کند.

علاوه بر این، terrariumElement که به این تابع منتقل می‌شود، یک رویداد pointerdown اختصاص داده می‌شود، که بخشی از وب APIها است که برای کمک به مدیریت DOM طراحی شده‌اند. onpointerdown زمانی اجرا می‌شود که یک دکمه فشار داده شود، یا در مورد ما، یک عنصر قابل کشیدن لمس شود. این هندلر رویداد در هر دو مرورگر وب و موبایل کار می‌کند، با چند استثنا.

هندلر رویداد onclick پشتیبانی بسیار بیشتری در مرورگرهای مختلف دارد؛ چرا اینجا از آن استفاده نمی‌کنید؟ به نوع دقیق تعامل صفحه‌ای که می‌خواهید ایجاد کنید فکر کنید.


تابع Pointerdrag

عنصر terrariumElement آماده کشیده شدن است؛ وقتی رویداد onpointerdown اجرا می‌شود، تابع pointerDrag فراخوانی می‌شود. این تابع را درست زیر این خط اضافه کنید: terrariumElement.onpointerdown = pointerDrag;:

وظیفه

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

چندین اتفاق می‌افتد. اول، شما با استفاده از e.preventDefault(); از وقوع رویدادهای پیش‌فرضی که معمولاً در pointerdown رخ می‌دهند، جلوگیری می‌کنید. به این ترتیب کنترل بیشتری بر رفتار رابط کاربری دارید.

وقتی فایل اسکریپت را به طور کامل ساختید، به این خط برگردید و آن را بدون e.preventDefault() امتحان کنید - چه اتفاقی می‌افتد؟

دوم، فایل index.html را در یک پنجره مرورگر باز کنید و رابط کاربری را بررسی کنید. وقتی روی یک گیاه کلیک می‌کنید، می‌توانید ببینید که رویداد 'e' چگونه ثبت می‌شود. به جزئیات رویداد نگاه کنید تا ببینید چقدر اطلاعات با یک رویداد pointerdown جمع‌آوری می‌شود!

سپس، توجه کنید که چگونه متغیرهای محلی pos3 و pos4 به e.clientX تنظیم می‌شوند. می‌توانید مقادیر e را در پنل بازرسی پیدا کنید. این مقادیر مختصات x و y گیاه را در لحظه‌ای که روی آن کلیک می‌کنید یا آن را لمس می‌کنید، ثبت می‌کنند. شما به کنترل دقیق رفتار گیاهان هنگام کلیک و کشیدن آن‌ها نیاز دارید، بنابراین مختصات آن‌ها را پیگیری می‌کنید.

آیا واضح‌تر شده است که چرا کل این برنامه با یک Closure بزرگ ساخته شده است؟ اگر اینطور نبود، چگونه می‌توانستید محدوده هر یک از ۱۴ گیاه قابل کشیدن را حفظ کنید؟

تابع اولیه را با افزودن دو دستکاری رویداد pointer دیگر زیر pos4 = e.clientY کامل کنید:

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

اکنون مشخص می‌کنید که می‌خواهید گیاه همراه با اشاره‌گر هنگام حرکت کشیده شود و حرکت کشیدن زمانی که گیاه را از انتخاب خارج می‌کنید متوقف شود. onpointermove و onpointerup همگی بخشی از همان API هستند که onpointerdown است. رابط کاربری اکنون خطاهایی ایجاد می‌کند زیرا هنوز توابع elementDrag و stopElementDrag را تعریف نکرده‌اید، بنابراین آن‌ها را در مرحله بعد بسازید.

توابع elementDrag و stopElementDrag

شما Closure خود را با افزودن دو تابع داخلی دیگر که مدیریت می‌کنند چه اتفاقی می‌افتد وقتی یک گیاه را می‌کشید و کشیدن آن را متوقف می‌کنید، کامل خواهید کرد. رفتاری که می‌خواهید این است که بتوانید هر گیاه را در هر زمان بکشید و آن را در هر جایی از صفحه قرار دهید. این رابط کاربری کاملاً بدون محدودیت است (مثلاً هیچ منطقه رهاسازی وجود ندارد) تا به شما اجازه دهد تراریوم خود را دقیقاً همانطور که دوست دارید طراحی کنید، با افزودن، حذف و جابه‌جایی گیاهان.

وظیفه

تابع 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';
}

در این تابع، بسیاری از موقعیت‌های اولیه ۱-۴ که به عنوان متغیرهای محلی در تابع خارجی تنظیم کرده‌اید، ویرایش می‌شوند. اینجا چه اتفاقی می‌افتد؟

هنگام کشیدن، 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 تنظیم نکنید؟

اکنون پروژه خود را تکمیل کرده‌اید!

🥇تبریک می‌گویم! شما تراریوم زیبای خود را به پایان رساندید. تراریوم نهایی


🚀چالش

یک هندلر رویداد جدید به Closure خود اضافه کنید تا کار دیگری با گیاهان انجام دهد؛ برای مثال، با دوبار کلیک روی یک گیاه، آن را به جلو بیاورید. خلاق باشید!

آزمون پس از درس

آزمون پس از درس

مرور و مطالعه شخصی

در حالی که کشیدن عناصر در صفحه به نظر ساده می‌رسد، روش‌های زیادی برای انجام این کار و مشکلات زیادی وجود دارد، بسته به اثری که دنبال می‌کنید. در واقع، یک API کشیدن و رها کردن کامل وجود دارد که می‌توانید امتحان کنید. ما از آن در این ماژول استفاده نکردیم زیرا اثری که می‌خواستیم کمی متفاوت بود، اما این API را روی پروژه خود امتحان کنید و ببینید چه چیزی می‌توانید به دست آورید.

اطلاعات بیشتری درباره رویدادهای اشاره‌گر در مستندات W3C و مستندات وب MDN پیدا کنید.

همیشه قابلیت‌های مرورگر را با استفاده از CanIUse.com بررسی کنید.

تکلیف

کمی بیشتر با DOM کار کنید


سلب مسئولیت:
این سند با استفاده از سرویس ترجمه هوش مصنوعی Co-op Translator ترجمه شده است. در حالی که ما برای دقت تلاش می‌کنیم، لطفاً توجه داشته باشید که ترجمه‌های خودکار ممکن است شامل خطاها یا نادرستی‌هایی باشند. سند اصلی به زبان اصلی آن باید به عنوان منبع معتبر در نظر گرفته شود. برای اطلاعات حساس، ترجمه حرفه‌ای انسانی توصیه می‌شود. ما هیچ مسئولیتی در قبال سوءتفاهم‌ها یا تفسیرهای نادرست ناشی از استفاده از این ترجمه نداریم.