90- آموزش جاوااسکریپت | پروژه عملی: قسمت 3 از 12- شروع ساختار ماژولهای پروژه Calorie Tracker
در این بخش، ساختار اولیه ماژولهای پروژه Calorie Tracker را با Module Pattern پیادهسازی میکنیم. همچنین فایل app.js را به پروژه متصل کرده، Item Controller را میسازیم و تابع init را برای راهاندازی اولیه برنامه آماده میکنیم.
در بخش قبل، رابط کاربری پروژه را با استفاده از Materialize CSS آماده کردیم.
در این بخش، وارد مرحله پیادهسازی ساختار JavaScript میشویم و پایه ماژولهای اصلی برنامه را میسازیم.
در ابتدای کار، باید فایل app.js را به فایل HTML متصل کنیم تا کدهای برنامه اجرا شوند. سپس با استفاده از Module Pattern، ساختار کلی پروژه را به چند کنترلر مستقل تقسیم میکنیم.
اتصال فایل app.js به HTML
ابتدا باید مطمئن شویم فایل JavaScript اصلی پروژه به صفحه متصل شده است. این فایل باید در انتهای body و بعد از اسکریپتهای jQuery و Materialize قرار بگیرد.
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script src="app.js"></script>
قرار دادن فایل app.js در این بخش باعث میشود که ابتدا وابستگیهای موردنیاز بارگذاری شوند و سپس کد اصلی برنامه اجرا شود.
ساختار کلی ماژولها
در این پروژه، کدها را به چند بخش اصلی تقسیم میکنیم تا مدیریت برنامه سادهتر و منظمتر باشد. این ماژولها عبارتاند از:
Storage Controllerبرای کار با Local StorageItem Controllerبرای مدیریت دادههای مربوط به آیتمهاUI Controllerبرای کنترل رابط کاربریApp Controllerبرای هماهنگسازی کل برنامه
در این بخش، ماژول Storage Controller را فقط در نظر میگیریم و پیادهسازی آن را به مراحل بعدی موکول میکنیم.
تعریف محل کنترلرها در فایل app.js
برای شروع، میتوانیم با چند کامنت ساختار کلی فایل را مشخص کنیم:
// Storage Controller
// Item Controller
// UI Controller
// App Controller
این کار باعث میشود از همان ابتدا معماری برنامه روشن باشد و هر بخش در جای مناسب خود توسعه پیدا کند.
شروع با Item Controller
اولین ماژولی که پیادهسازی میکنیم، Item Controller است.
این ماژول مسئول مدیریت دادههای مربوط به وعدههای غذایی و کالریها خواهد بود.
برای ساخت این ماژول از IIFE یا همان Immediately Invoked Function Expression استفاده میکنیم.
const ItemCtrl = (function () {
})();
IIFE چیست؟
IIFE یک تابع است که بلافاصله پس از تعریف، اجرا میشود.
این الگو به ما کمک میکند:
- متغیرها و دادههای داخلی را خصوصی نگه داریم
- فقط متدهای موردنیاز را در اختیار بخشهای دیگر قرار دهیم
- از شلوغشدن فضای سراسری برنامه جلوگیری کنیم
تعریف UI Controller
بههمین شکل، کنترلر رابط کاربری را نیز تعریف میکنیم:
const UICtrl = (function () {
})();
این بخش در ادامه مسئول کارهایی مانند:
- دریافت مقادیر فرم
- نمایش یا مخفیکردن دکمهها
- رندر کردن آیتمها در لیست
- بهروزرسانی مجموع کالریها
خواهد بود.
تعریف App Controller
در مرحله بعد، یک کنترلر اصلی برای هماهنگکردن بخشهای مختلف برنامه میسازیم. این ماژول، کنترلرهای دیگر را دریافت میکند و نقطه اتصال بخشهای مختلف برنامه خواهد بود.
const App = (function (ItemCtrl, UICtrl) {
})(ItemCtrl, UICtrl);
در ادامه، زمانی که Storage Controller را نیز پیادهسازی کنیم، آن را هم به این ماژول اضافه خواهیم کرد.
ساخت سازنده Item
برای اینکه بتوانیم آیتمهای جدید بسازیم، به یک سازنده نیاز داریم. هر آیتم شامل سه ویژگی اصلی است:
idnamecalories
کد سازنده به این صورت خواهد بود:
const ItemCtrl = (function () {
const Item = function (id, name, calories) {
this.id = id;
this.name = name;
this.calories = calories;
};
})();
این سازنده هر بار که یک آیتم جدید ایجاد شود، شیئی با این سه ویژگی تولید میکند.
تعریف ساختار داده برنامه
بعد از سازنده، باید یک ساختار داده برای نگهداری اطلاعات برنامه داشته باشیم. این ساختار، نقش state داخلی برنامه را ایفا میکند.
const ItemCtrl = (function () {
const Item = function (id, name, calories) {
this.id = id;
this.name = name;
this.calories = calories;
};
const data = {
items: [],
currentItem: null,
totalCalories: 0
};
})();
اجزای data
این آبجکت شامل سه بخش اصلی است:
1. items
آرایهای از همه آیتمهای ثبتشده در برنامه
2. currentItem
آیتمی که در حال حاضر برای ویرایش انتخاب شده است
3. totalCalories
مجموع کالری همه آیتمها
تعریف دادههای اولیه
برای شروع و آزمایش منطق برنامه، میتوانیم چند آیتم نمونه را بهصورت موقت در data.items قرار دهیم:
const ItemCtrl = (function () {
const Item = function (id, name, calories) {
this.id = id;
this.name = name;
this.calories = calories;
};
const data = {
items: [
{ id: 0, name: 'Steak Dinner', calories: 1200 },
{ id: 1, name: 'Cookie', calories: 400 },
{ id: 2, name: 'Eggs', calories: 300 }
],
currentItem: null,
totalCalories: 0
};
})();
این دادهها فقط برای شروع کار و تست ساختار استفاده میشوند و در ادامه بهصورت پویا از طریق فرم به برنامه اضافه خواهند شد.
مفهوم private و public در Module Pattern
یکی از مهمترین ویژگیهای Module Pattern این است که متغیرها و توابعی که داخل ماژول تعریف میشوند، بهصورت پیشفرض خصوصی هستند.
برای مثال، اگر data را داخل ItemCtrl تعریف کنیم، از بیرون ماژول به آن دسترسی مستقیم نخواهیم داشت.
برای در دسترس قرار دادن بخشی از قابلیتهای ماژول، باید آنها را در return برگردانیم.
ساخت متد logData
برای آزمایش و مشاهده دادههای داخلی، یک متد عمومی به نام logData میسازیم که data را برگرداند.
const ItemCtrl = (function () {
const Item = function (id, name, calories) {
this.id = id;
this.name = name;
this.calories = calories;
};
const data = {
items: [
{ id: 0, name: 'Steak Dinner', calories: 1200 },
{ id: 1, name: 'Cookie', calories: 400 },
{ id: 2, name: 'Eggs', calories: 300 }
],
currentItem: null,
totalCalories: 0
};
return {
logData: function () {
return data;
}
};
})();
اکنون این متد از بیرون ماژول قابلدسترسی است.
تست ItemCtrl
برای بررسی عملکرد ماژول، میتوانیم در کنسول یا در بخشی از برنامه، متد logData را فراخوانی کنیم:
console.log(ItemCtrl.logData());
خروجی این دستور، ساختار کامل دادههای داخلی ماژول را نمایش میدهد.
بازگرداندن متد init در App Controller
ماژول App قرار است فقط یک متد اصلی به نام init را در اختیار قرار دهد.
این متد برای راهاندازی اولیه برنامه استفاده میشود.
const App = (function (ItemCtrl, UICtrl) {
return {
init: function () {
console.log('Initializing App...');
}
};
})(ItemCtrl, UICtrl);
اجرای init
پس از تعریف App، میتوانیم متد init را فراخوانی کنیم تا مطمئن شویم ساختار برنامه بهدرستی اجرا میشود.
App.init();
اگر همه چیز درست باشد، هنگام بارگذاری صفحه، پیام زیر در کنسول نمایش داده میشود:
Initializing App...
نقش init در برنامه
تابع init محل اجرای عملیات اولیه برنامه است. در ادامه، کارهایی مانند موارد زیر را در این تابع قرار میدهیم:
- دریافت آیتمها از
Item Controller - نمایش آیتمها در رابط کاربری
- ریستکردن حالت ویرایش
- ثبت event listenerهای اولیه
- آمادهسازی وضعیت شروع برنامه
در واقع، هر چیزی که باید هنگام بارگذاری اولیه برنامه اجرا شود، در این متد قرار میگیرد.
نسخه کامل کد این بخش
در پایان این مرحله، کد app.js بهشکل زیر خواهد بود:
// Storage Controller
// Item Controller
const ItemCtrl = (function () {
const Item = function (id, name, calories) {
this.id = id;
this.name = name;
this.calories = calories;
};
const data = {
items: [
{ id: 0, name: 'Steak Dinner', calories: 1200 },
{ id: 1, name: 'Cookie', calories: 400 },
{ id: 2, name: 'Eggs', calories: 300 }
],
currentItem: null,
totalCalories: 0
};
return {
logData: function () {
return data;
}
};
})();
// UI Controller
const UICtrl = (function () {
return {};
})();
// App Controller
const App = (function (ItemCtrl, UICtrl) {
return {
init: function () {
console.log('Initializing App...');
console.log(ItemCtrl.logData());
}
};
})(ItemCtrl, UICtrl);
App.init();
جمعبندی
در این بخش، ساختار اولیه JavaScript پروژه Calorie Tracker را با استفاده از Module Pattern ایجاد کردیم. در این مرحله:
- فایل
app.jsرا به HTML متصل کردیم - ساختار کلی کنترلرها را مشخص کردیم
- ماژول
Item Controllerرا ایجاد کردیم - سازنده
Itemرا نوشتیم - ساختار
dataرا بهعنوان state داخلی برنامه تعریف کردیم - متد
logDataرا برای تست دادهها ساختیم - ماژول
Appو متدinitرا پیادهسازی کردیم
در بخش بعدی، متد دریافت آیتمها را در Item Controller ایجاد میکنیم و سپس دادهها را با کمک UI Controller در رابط کاربری نمایش خواهیم داد.