|
|
7 months ago | |
|---|---|---|
| .. | ||
| README.md | 7 months ago | |
| assignment.md | 7 months ago | |
README.md
ساخت یک برنامه بانکی بخش ۱: قالبهای HTML و مسیرها در یک برنامه وب
journey
title سفر توسعه اپلیکیشن بانکی شما
section مبانی SPA
درک برنامههای تک صفحهای: 3: Student
یادگیری مفاهیم قالب: 4: Student
تسلط بر دستکاری DOM: 4: Student
section سیستمهای مسیردهی
پیادهسازی مسیردهی سمت مشتری: 4: Student
مدیریت تاریخچه مرورگر: 5: Student
ایجاد سیستمهای ناوبری: 5: Student
section الگوهای حرفهای
ساخت معماری مدولار: 5: Student
اعمال بهترین روشها: 5: Student
خلق تجربههای کاربری: 5: Student
وقتی رایانه هدایت آپولو ۱۱ در سال ۱۹۶۹ به ماه ناوبری میکرد، باید بدون راهاندازی مجدد کل سیستم بین برنامههای مختلف جابجا میشد. برنامههای وب مدرن به همین شکل کار میکنند – آنها آنچه را که میبینید بدون بارگذاری مجدد کامل تغییر میدهند. این تجربهای روان و پاسخگو ایجاد میکند که کاربران امروزی انتظار دارند.
برخلاف وبسایتهای سنتی که برای هر تعامل کل صفحه را بارگذاری میکنند، برنامههای وب مدرن تنها بخشهایی را که نیاز به تغییر دارند بهروزرسانی میکنند. این رویکرد، درست مانند اینکه مرکز کنترل مأموریت بین نمایشهای مختلف جابجا میشود در حالی که ارتباط مداوم حفظ میشود، آن تجربه روانی را که ما انتظار داریم ایجاد میکند.
در اینجا تفاوت به قدری چشمگیر است که:
| برنامههای چندصفحهای سنتی | برنامههای تکصفحهای مدرن |
|---|---|
| ناوبری | بارگذاری کامل صفحه برای هر صفحه |
| عملکرد | کندتر به دلیل بارگذاری کامل HTML |
| تجربه کاربری | چشمکهای آزاردهنده صفحه |
| اشتراک داده | دشوار بین صفحات |
| توسعه | چندین فایل HTML برای نگهداری |
درک تکامل:
- برنامههای سنتی نیاز به درخواست سرور برای هر عمل ناوبری دارند
- برنامههای مدرن تکصفحهای یک بار بارگذاری میشوند و محتوا را پویا با جاوااسکریپت بهروزرسانی میکنند
- انتظارات کاربران اکنون به تعاملات فوری و بدون درز گرایش دارد
- مزایای عملکردی شامل کاهش پهنای باند و پاسخ سریعتر میشود
در این درس، یک برنامه بانکی با چند صفحه خواهیم ساخت که بهطور روان با هم جریان دارند. درست مانند اینکه دانشمندان از ابزارهای ماژولار استفاده میکنند که میتوان آنها را برای آزمایشهای مختلف پیکربندی مجدد کرد، ما از قالبهای HTML به عنوان اجزای قابل استفاده مجدد استفاده خواهیم کرد که در صورت نیاز نمایش داده میشوند.
شما با قالبهای HTML (طرحهای قابل استفاده مجدد برای صفحات مختلف)، مسیریابی جاوااسکریپت (سیستمی که بین صفحات جابجا میشود) و رابط تاریخچه مرورگر (که دکمه بازگشت را به درستی کار میکند) کار خواهید کرد. اینها همان تکنیکهای اساسی هستند که فریمورکهایی مانند React، Vue و Angular استفاده میکنند.
در پایان، یک برنامه بانکی عملی خواهید داشت که اصول برنامههای تکصفحهای حرفهای را نشان میدهد.
mindmap
root((برنامههای تکصفحهای))
Architecture
Template System
Client-side Routing
State Management
Event Handling
Templates
Reusable Components
Dynamic Content
DOM Manipulation
Content Switching
Routing
URL Management
History API
Navigation Logic
Browser Integration
User Experience
ناوبری سریع
انتقالات روان
وضعیت یکدست
تعاملات مدرن
Performance
کاهش درخواستهای سرور
انتقالات سریعتر صفحه
استفادهٔ بهینه از منابع
پاسخگویی بهتر
آزمون قبل از درس
چیزی که نیاز خواهید داشت
ما به یک سرور وب محلی برای آزمایش برنامه بانکیمان نیاز داریم – نگران نباشید، آسانتر از آن است که فکر میکنید! اگر قبلاً یکی ندارید، فقط Node.js را نصب کنید و از پوشه پروژه خود npx lite-server را اجرا کنید. این فرمان مفید یک سرور محلی راهاندازی میکند و بهطور خودکار برنامه شما را در مرورگر باز میکند.
آمادهسازی
در کامپیوترتان، یک پوشه به نام bank بسازید و یک فایل با نام index.html داخل آن ایجاد کنید. ما از این قالب اولیه HTML شروع خواهیم کرد:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bank App</title>
</head>
<body>
<!-- This is where you'll work -->
</body>
</html>
این قالب اولیه چه چیزهایی فراهم میکند:
- ساختار سند HTML5 را با اعلان مناسب DOCTYPE برقرار میکند
- کدگذاری کاراکتر را به UTF-8 برای پشتیبانی از متنهای بینالمللی تنظیم میکند
- طراحی ریسپانسیو را با تگ متا viewport برای سازگاری موبایل فعال میکند
- عنوان توصیفی که در تب مرورگر ظاهر میشود تنظیم میکند
- بخش بدنه تمیزی ایجاد میکند که برای ساخت برنامه استفاده میشود
📁 پیشنمایش ساختار پروژه
تا پایان این درس، پروژه شما شامل موارد زیر خواهد بود:
bank/ ├── index.html <!-- Main HTML with templates --> ├── app.js <!-- Routing and navigation logic --> └── style.css <!-- (Optional for future lessons) -->وظایف فایلها:
- index.html: شامل همه قالبها و ساختار برنامه
- app.js: مدیریت مسیرها، ناوبری و قالبها
- قالبها: تعریف رابط کاربری برای صفحه ورود، داشبورد و سایر صفحات
قالبهای HTML
قالبها یک مشکل اساسی در توسعه وب را حل میکنند. وقتی گوتنبرگ در دهه ۱۴۴۰ چاپ متحرک را اختراع کرد، متوجه شد به جای حکاکی کل صفحات، میتواند بلوکهای قابل استفاده مجدد حروف بسازد و به صورت دلخواه بچیند. قالبهای HTML بر همان اصل کار میکنند – به جای ایجاد فایلهای HTML جداگانه برای هر صفحه، شما ساختارهای قابل استفاده مجددی تعریف میکنید که در صورت نیاز نمایش داده میشوند.
flowchart TD
A["📋 تعریف قالب"] --> B["💬 مخفی در DOM"]
B --> C["🔍 جاوااسکریپت قالب را پیدا میکند"]
C --> D["📋 کلون کردن محتوای قالب"]
D --> E["🔗 الصاق به DOM قابل مشاهده"]
E --> F["👁️ کاربر محتوا را میبیند"]
G["قالب ورود"] --> A
H["قالب داشبورد"] --> A
I["قالبهای آینده"] --> A
style A fill:#e3f2fd
style D fill:#e8f5e8
style F fill:#fff3e0
style B fill:#f3e5f5
قالبها را مانند نقشههای یک طرح برای بخشهای مختلف برنامه خود در نظر بگیرید. همانطور که یک معمار یک نقشه را میسازد و بارها استفاده میکند به جای اینکه اتاقهای یکسان را دوباره ترسیم کند، ما نیز قالبها را یک بار میسازیم و در صورت نیاز نمونهسازی میکنیم. مرورگر این قالبها را مخفی نگه میدارد تا زمانی که جاوااسکریپت آنها را فعال کند.
اگر میخواهید چند صفحه برای یک وبسایت بسازید، یک راه حل این است که برای هر صفحه یک فایل HTML جداگانه ایجاد کنید. اما این راه حل معایبی دارد:
- باید هنگام جابجایی صفحه، کل HTML دوباره بارگذاری شود که ممکن است کند باشد.
- به اشتراک گذاشتن داده بین صفحات مختلف دشوار است.
رویکرد دیگر این است که تنها یک فایل HTML داشته باشید و چندین قالب HTML با استفاده از عنصر <template> تعریف کنید. قالب، بلوک HTML قابل استفاده مجددی است که توسط مرورگر نمایش داده نمیشود و باید در زمان اجرا با جاوااسکریپت نمونهسازی شود.
بیایید بسازیم
ما قصد داریم یک برنامه بانکی با دو صفحه اصلی بسازیم: صفحه ورود و داشبورد. ابتدا، یک المان جایگزین در بدنه HTML اضافه میکنیم – جایی که همه صفحات ما نمایش داده خواهند شد:
<div id="app">Loading...</div>
درک این المان جایگزین:
- یک ظرف با شناسه "app" ایجاد میکند که همه صفحات در آن نمایش داده میشوند
- یک پیام بارگذاری نمایش میدهد تا زمانی که جاوااسکریپت صفحه اول را مقداردهی کند
- یک نقطه نصب واحد برای محتوای پویا فراهم میکند
- هدفگیری آسان با استفاده از
document.getElementById()را ممکن میکند
💡 نکته حرفهای: از آنجایی که محتوای این عنصر جایگزین خواهد شد، میتوانیم یک پیام یا نشانگر بارگذاری بگذاریم که هنگام بارگذاری برنامه نمایش داده شود.
سپس قالب HTML صفحه ورود را زیر آن اضافه میکنیم. فعلاً فقط یک عنوان و یک بخش حاوی یک لینک برای انجام ناوبری قرار میدهیم.
<template id="login">
<h1>Bank App</h1>
<section>
<a href="/dashboard">Login</a>
</section>
</template>
شکستن این قالب ورود:
- یک قالب با شناسه منحصربهفرد "login" برای هدفگیری جاوااسکریپت تعریف میکند
- یک تیتر اصلی که برند برنامه را مشخص میکند شامل میشود
- یک عنصر معنایی
<section>برای گروهبندی محتوا دارد - یک لینک ناوبری ارائه میدهد که کاربران را به داشبورد هدایت میکند
بعد قالب دیگری برای صفحه داشبورد اضافه میکنیم. این صفحه شامل بخشهای متفاوتی است:
- یک سربرگ با عنوان و لینک خروج
- موجودی حساب فعلی
- فهرستی از تراکنشها که در جدول نمایش داده میشود
<template id="dashboard">
<header>
<h1>Bank App</h1>
<a href="/login">Logout</a>
</header>
<section>
Balance: 100$
</section>
<section>
<h2>Transactions</h2>
<table>
<thead>
<tr>
<th>Date</th>
<th>Object</th>
<th>Amount</th>
</tr>
</thead>
<tbody></tbody>
</table>
</section>
</template>
درک هر بخش این داشبورد:
- صفحه را با یک عنصر معنایی
<header>که شامل ناوبری است ساختار میدهد - عنوان برنامه را به صورت یکنواخت در صفحات نمایش میدهد
- یک لینک خروج ارائه میدهد که به صفحه ورود باز میگردد
- موجودی فعلی حساب در بخشی اختصاصی نمایش داده میشود
- دادههای تراکنشها را با استفاده از یک جدول HTML به طور مناسب سازماندهی میکند
- هدرهای جدول برای ستونهای تاریخ، شیء و مبلغ تعریف شدهاند
- بدنه جدول خالی گذاشته شده تا محتوای پویا بعداً تزریق شود
💡 نکته حرفهای: هنگام ایجاد قالبهای HTML، اگر میخواهید ببینید چگونه به نظر میرسند، میتوانید تگهای
<template>و</template>را با<!-- -->کامنت کنید.
🔄 بررسی آموزشی
درک سیستم قالب: قبل از اجرای جاوااسکریپت، مطمئن شوید که میدانید:
- ✅ قالبها چگونه از عناصر HTML معمولی متفاوتند
- ✅ چرا قالبها تا وقتی که جاوااسکریپت آنها را فعال نکند مخفی باقی میمانند
- ✅ اهمیت ساختار معنایی HTML در قالبها
- ✅ چگونه قالبها امکان استفاده مجدد از اجزای رابط کاربری را فراهم میکنند
آزمون سریع خودآزمایی: اگر تگهای <template> را از اطراف HTML حذف کنید چه اتفاقی میافتد؟
پاسخ: محتوا بلافاصله قابل مشاهده میشود و عملکرد قالب خود را از دست میدهد
مزایای معماری: قالبها فراهم میکنند:
- استفاده مجدد: یک تعریف، چندین نمونه
- عملکرد: بدون پردازش HTML اضافی
- نگهداریپذیری: ساختار مرکزی UI
- انعطافپذیری: جابجایی محتوای پویا
✅ چرا فکر میکنید که به قالبها id دادهایم؟ آیا میتوانستیم به جای آن از کلاس استفاده کنیم؟
زنده کردن قالبها با جاوااسکریپت
حالا باید قالبهای خود را قابل استفاده کنیم. درست مانند چاپگر سهبعدی که نقشه دیجیتال را به جسم فیزیکی تبدیل میکند، جاوااسکریپت قالبهای پنهان ما را به عناصری قابل مشاهده و تعاملی تبدیل میکند که کاربران میتوانند ببینند و استفاده کنند.
این روند از سه مرحله ثابت تشکیل شده که پایه توسعه وب مدرن را تشکیل میدهد. وقتی این الگو را درک کنید، آن را در بسیاری از فریمورکها و کتابخانهها خواهید شناخت.
اگر فایل HTML فعلی خود را در مرورگر باز کنید، خواهید دید که روی Loading... گیر میکند. این به این دلیل است که باید مقداری کد جاوااسکریپت اضافه کنیم تا قالبهای HTML را نمونهسازی و نمایش دهد.
نمونهسازی قالب معمولاً در ۳ مرحله انجام میشود:
- دریافت عنصر قالب در درخت DOM، مثلاً با استفاده از
document.getElementById. - کپی کردن کل قالب با
cloneNode. - الصاق آن به DOM زیر یک عنصر قابل مشاهده، مثلاً با استفاده از
appendChild.
flowchart TD
A[🔍 گام ۱: پیدا کردن قالب] --> B[📋 گام ۲: کلون کردن قالب]
B --> C[🔗 گام ۳: ضمیمه کردن به DOM]
A1["document.getElementById('login')"] --> A
B1["template.content.cloneNode(true)"] --> B
C1["app.appendChild(view)"] --> C
C --> D[👁️ قالب قابل مشاهده برای کاربر]
style A fill:#e1f5fe
style B fill:#f3e5f5
style C fill:#e8f5e8
style D fill:#fff3e0
تحلیل بصری فرآیند:
- گام ۱ قالب پنهان را در ساختار DOM پیدا میکند
- گام ۲ یک کپی عملیاتی ایجاد میکند که میتوان آن را بهطور ایمن تغییر داد
- گام ۳ کپی را در صفحه قابل مشاهده درج میکند
- نتیجه یک صفحه کاربردی است که کاربران میتوانند با آن تعامل داشته باشند
✅ چرا قبل از الصاق به DOM باید قالب را کپی کنیم؟ فکر میکنید اگر این مرحله را رد کنیم چه اتفاقی میافتد؟
وظیفه
یک فایل جدید به نام app.js در پوشه پروژه خود ایجاد کنید و آن فایل را در بخش <head> فایل HTML خود وارد کنید:
<script src="app.js" defer></script>
درک واردکردن این اسکریپت:
- فایل جاوااسکریپت را به سند HTML ما متصل میکند
- از ویژگی
deferاستفاده میکند تا اطمینان حاصل شود اسکریپت پس از پایان تحلیل HTML اجرا شود - دسترسی به همه عناصر DOM را فعال میکند چون قبل از اجرای اسکریپت کاملاً بارگذاری شدهاند
- مستلزم بهترین روشهای مدرن بارگذاری اسکریپت و عملکرد است
حالا در app.js، یک تابع جدید به نام updateRoute ایجاد خواهیم کرد:
function updateRoute(templateId) {
const template = document.getElementById(templateId);
const view = template.content.cloneNode(true);
const app = document.getElementById('app');
app.innerHTML = '';
app.appendChild(view);
}
گام به گام، اینجا چه میگذرد:
- المان قالب را با استفاده از
idمنحصر به فردش پیدا میکند - یک کپی عمیق از محتوای قالب با
cloneNode(true)میسازد - ظرف برنامه را که محتوا نمایش داده خواهد شد، پیدا میکند
- هر محتوای موجود در ظرف برنامه را پاک میکند
- محتوای قالب کپی شده را در DOM قابل مشاهده درج میکند
حالا این تابع را با یکی از قالبها صدا بزنید و نتیجه را ببینید.
updateRoute('login');
آنچه این فراخوانی تابع انجام میدهد:
- قالب ورود را با ارسال شناسهاش بهعنوان پارامتر فعال میکند
- نشان میدهد چگونه میتوان به صورت برنامهریزیشده بین صفحات مختلف برنامه جابجا شد
- صفحه ورود را به جای پیام "Loading..." نمایش میدهد
✅ هدف از این کد app.innerHTML = ''; چیست؟ بدون آن چه اتفاقی میافتد؟
ایجاد مسیرها
مسیریابی اساساً اتصال URLها به محتوای مناسب است. تصور کنید اپراتورهای تلفن قدیمی چگونه با سوئیچبورد تماسها را وصل میکردند – آنها درخواست ورودی را گرفته و به مقصد صحیح متصل میکردند. مسیریابی وب به همین شکل کار میکند: درخواست URL را میگیرد و مشخص میکند چه محتوایی نمایش داده شود.
flowchart LR
A["🌐 مسیر URL<br/>/dashboard"] --> B["🗺️ شیء مسیرها<br/>جستجو"]
B --> C["🎯 شناسه قالب<br/>'dashboard'"]
C --> D["📌 یافتن قالب<br/>getElementById"]
D --> E["👁️ نمایش صفحه<br/>کپی و الحاق"]
F["📍 /login"] --> G["🎯 'login'"]
H["📍 /unknown"] --> I["❌ پیدا نشد"]
I --> J["🔄 هدایت به /login"]
style B fill:#e3f2fd
style E fill:#e8f5e8
style I fill:#ffebee
style J fill:#fff3e0
معمولاً سرورهای وب این کار را با سرو کردن فایلهای HTML مختلف برای URLهای مختلف انجام میدادند. از آنجا که ما یک برنامه تک صفحهای میسازیم، باید این مسیریابی را خودمان با جاوااسکریپت انجام دهیم. این رویکرد کنترل بیشتری روی تجربه کاربری و عملکرد به ما میدهد.
flowchart LR
A["🌐 مسیر URL<br/>/dashboard"] --> B["🗺️ شیء مسیرها<br/>جستجو"]
B --> C["🎯 شناسه الگو<br/>'dashboard'"]
C --> D["📄 یافتن الگو<br/>getElementById"]
D --> E["👁️ نمایش صفحه<br/>رونوشت و افزودن"]
F["📍 /login"] --> G["🎯 'login'"]
H["📍 /unknown"] --> I["❌ یافت نشد"]
I --> J["🔄 هدایت مجدد به /login"]
style B fill:#e3f2fd
style E fill:#e8f5e8
style I fill:#ffebee
style J fill:#fff3e0
درک جریان مسیریابی:
- تغییرات URL باعث جستجو در پیکربندی مسیرها میشود
- مسیرهای معتبر به شناسههای قالب خاص برای رندر شدن نگاشت میشوند
- مسیرهای نامعتبر موجب فعال شدن رفتار پشتیبان برای جلوگیری از حالتهای شکسته میشوند
- رندر قالب بر اساس فرآیند سه مرحلهای که قبلاً آموختیم انجام میشود
وقتی درباره یک برنامه وب صحبت میکنیم، مسیردهی به معنای نگاشت URLها به صفحات خاصی است که باید نمایش داده شوند. روی یک وبسایت با چند فایل HTML، این به طور خودکار انجام میشود چون مسیر فایلها در URL منعکس میشود. برای مثال، با این فایلها در پوشه پروژه شما:
mywebsite/index.html
mywebsite/login.html
mywebsite/admin/index.html
اگر سرور وبی با ریشه mywebsite بسازید، نگاشت URL به صورت زیر خواهد بود:
https://site.com --> mywebsite/index.html
https://site.com/login.html --> mywebsite/login.html
https://site.com/admin/ --> mywebsite/admin/index.html
اما برای برنامه وب ما که از یک فایل HTML واحد شامل همه صفحات استفاده میکنیم، این رفتار پیشفرض به ما کمکی نمیکند. باید این نگاشت را به صورت دستی بسازیم و قالب نمایش داده شده را با جاوااسکریپت بهروزرسانی کنیم.
وظیفه
ما از یک شی ساده برای پیادهسازی نگاشت بین مسیرهای URL و قالبهایمان استفاده خواهیم کرد. این شی را در بالای فایل app.js خود اضافه کنید.
const routes = {
'/login': { templateId: 'login' },
'/dashboard': { templateId: 'dashboard' },
};
درک این پیکربندی مسیرها:
- نگاشت بین مسیرهای URL و شناسههای قالب را تعریف میکند
- از نحو شی استفاده میکند که کلیدها مسیرهای URL و مقادیر شامل اطلاعات قالب هستند
- جستجوی آسان قالب برای نمایش در هر URL را ممکن میسازد
- ساختاری مقیاسپذیر برای افزودن مسیرهای جدید در آینده فراهم میکند
حالا بیایید کمی تابع
updateRouteرا تغییر دهیم. به جای اینکه مستقیمtemplateIdرا به عنوان آرگومان بفرستیم، میخواهیم ابتدا آن را با نگاه کردن به URL فعلی به دست آوریم، سپس با استفاده از نقشه خود مقدار ID قالب مربوطه را دریافت کنیم. میتوانیم ازwindow.location.pathnameاستفاده کنیم تا فقط بخش مسیر URL را دریافت کنیم.
function updateRoute() {
const path = window.location.pathname;
const route = routes[path];
const template = document.getElementById(route.templateId);
const view = template.content.cloneNode(true);
const app = document.getElementById('app');
app.innerHTML = '';
app.appendChild(view);
}
توضیح گام به گام آنچه اینجا اتفاق میافتد:
- استخراج مسیر فعلی از URL مرورگر با استفاده از
window.location.pathname - جستجو پیکربندی مسیر متناظر در شیء routes ما
- دریافت شناسه قالب از پیکربندی مسیر
- پیروی از همان فرآیند رندر قالب مثل قبلاً
- ایجاد یک سیستم پویا که به تغییرات URL واکنش نشان میدهد
ما در اینجا مسیرهای اعلامشده را به قالب مربوطه نگاشتیم. میتوانید امتحان کنید که این کار به درستی کار میکند با تغییر دستی URL در مرورگر خود.
✅ چه اتفاقی میافتد اگر مسیری ناشناخته در URL وارد کنید؟ چگونه میتوانیم این مشکل را حل کنیم؟
افزودن ناوبری
با تأسیس مسیر یابی، کاربران به روشی برای ناوبری در برنامه نیاز دارند. وبسایتهای سنتی هنگام کلیک روی لینکها صفحه را به طور کامل بارگذاری مجدد میکنند، اما ما میخواهیم URL و محتوا را بدون بارگذاری مجدد صفحه بهروزرسانی کنیم. این تجربه روانتری ایجاد میکند، مشابه نحوه تغییر نماها در برنامههای دسکتاپ.
ما باید دو چیز را هماهنگ کنیم: بهروزرسانی URL مرورگر تا کاربران بتوانند صفحات را علامتگذاری و لینکها را به اشتراک بگذارند، و نمایش محتوای مناسب. وقتی به درستی پیادهسازی شود، این ناوبری یکپارچه ایجاد میکند که کاربران از برنامههای مدرن انتظار دارند.
sequenceDiagram
participant User
participant Browser
participant App
participant Template
User->>Browser: کلیک روی لینک "ورود"
Browser->>App: رویداد onclick فعال شد
App->>App: preventDefault() و navigate('/dashboard')
App->>Browser: history.pushState('/dashboard')
Browser->>Browser: URL به /dashboard بهروزرسانی شد
App->>App: فراخوانی updateRoute()
App->>Template: پیدا کردن و شبیهسازی قالب داشبورد
Template->>App: بازگرداندن محتوای شبیهسازی شده
App->>Browser: جایگزینی محتوای برنامه با قالب
Browser->>User: نمایش صفحه داشبورد
Note over User,Template: کاربر روی دکمه بازگشت مرورگر کلیک میکند
User->>Browser: کلیک روی دکمه بازگشت
Browser->>Browser: تاریخچه به /login بازگشت
Browser->>App: رویداد popstate فعال شد
App->>App: فراخوانی خودکار updateRoute()
App->>Template: پیدا کردن و شبیهسازی قالب ورود
Template->>App: بازگرداندن محتوای شبیهسازی شده
App->>Browser: جایگزینی محتوای برنامه با قالب
Browser->>User: نمایش صفحه ورود
🔄 بررسی آموزشی
معماری برنامه تک صفحهای (SPA): درک کامل سیستم را بررسی کنید:
- ✅ ناوبری سمت کلاینت چگونه با ناوبری سنتی سمت سرور متفاوت است؟
- ✅ چرا API تاریخچه (History API) برای ناوبری صحیح SPA ضروری است؟
- ✅ چگونه قالبها امکان ارائه محتوای داینامیک بدون بارگذاری مجدد صفحه را فراهم میکنند؟
- ✅ نقش مدیریت رویداد در جلوگیری از ناوبری پیشفرض چیست؟
یکپارچگی سیستم: SPA شما نشان میدهد:
- مدیریت قالب: کامپوننتهای UI قابل استفاده مجدد با محتوای داینامیک
- مسیریابی سمت کلاینت: مدیریت URL بدون درخواست به سرور
- معماری مبتنی بر رویداد: ناوبری و تعاملات پاسخگو
- یکپارچگی با مرورگر: پشتیبانی مناسب از دکمههای رفت و برگشت تاریخچه
- بهینهسازی عملکرد: انتقالات سریع و بار سرور کمتر
الگوهای حرفهای: شما اجرا کردهاید:
- جداسازی مدل-نما: قالبها جدا از منطق برنامه
- مدیریت حالت: حالات URL با محتوای نمایش داده شده همگام شده است
- بهبود تدریجی: استفاده از جاوااسکریپت برای ارتقاء عملکرد پایه HTML
- تجربه کاربری: ناوبری روان و شبیه برنامه بدون بارگذاری صفحه
💡 بینش معماری: اجزای سیستم ناوبری
آنچه در حال ساخت آن هستید:
- 🔄 مدیریت URL: بهروزرسانی نوار آدرس مرورگر بدون بارگذاری صفحه
- 📋 سیستم قالب: تعویض محتوای پویا بر اساس مسیر کنونی
- 📚 یکپارچگی تاریخچه: حفظ عملکرد دکمههای پشت و جلو مرورگر
- 🛡️ مدیریت خطا: راهکارهای جایگزین برای مسیرهای نامعتبر یا مفقود
نحوه عملکرد اجزا با هم:
- گوش دادن به رویدادهای ناوبری (کلیکها، تغییرات تاریخچه)
- بهروزرسانی URL به کمک History API
- رندر قالب مناسب برای مسیر جدید
- حفظ تجربه کاربری بدون نقص در کل
گام بعدی برای برنامه ما اضافه کردن امکان ناوبری بین صفحات بدون نیاز به تغییر دستی URL است. این دو چیز را نیاز دارد:
- بهروزرسانی URL فعلی
- بهروزرسانی قالب نمایش داده شده بر اساس URL جدید
ما قبلاً قسمت دوم را با تابع updateRoute به عهده گرفتیم، پس باید راهی پیدا کنیم که URL فعلی را بهروزرسانی کنیم.
باید از جاوااسکریپت و به طور خاص history.pushState استفاده کنیم که امکان بهروزرسانی URL و ایجاد ورودی جدید در تاریخچه مرورگر را بدون بارگذاری مجدد HTML میدهد.
⚠️ توجه مهم: در حالی که تگ HTML anchor
<a href>میتواند به تنهایی برای ایجاد لینک به URLهای مختلف استفاده شود، این باعث میشود مرورگر به صورت پیشفرض HTML صفحه را بارگذاری مجدد کند. هنگام مدیریت مسیریابی با جاوااسکریپت سفارشی، باید این رفتار را با استفاده از تابع preventDefault() در رویداد کلیک جلوگیری کنیم.
کار
بیایید یک تابع جدید بسازیم که بتوانیم در برنامه برای ناوبری استفاده کنیم:
function navigate(path) {
window.history.pushState({}, path, path);
updateRoute();
}
درک این تابع ناوبری:
- بهروزرسانی URL مرورگر به مسیر جدید با استفاده از
history.pushState - افزودن یک ورودی جدید به تاریخچه مرورگر برای پشتیبانی صحیح از دکمههای عقب/جلو
- شبیهسازی فراخوانی تابع
updateRoute()برای نمایش قالب مربوطه - ادامه تجربه برنامه تک صفحهای بدون بارگذاری مجدد صفحه
این روش ابتدا URL فعلی را بر اساس مسیر داده شده بهروزرسانی میکند و سپس قالب را بهروزرسانی میکند. خصوصیت window.location.origin ریشه URL را برمیگرداند که اجازه میدهد یک URL کامل از مسیر داده شده ساخته شود.
حالا که این تابع را داریم، میتوانیم مشکل مسیرهایی که با هیچ مسیری تعریف شده تطابق ندارد را بررسی کنیم. تابع updateRoute را با اضافه کردن یک مسیر جایگزین که از بین مسیرهای موجود انتخاب میکند اصلاح خواهیم کرد اگر نتوانیم تطابقی پیدا کنیم.
function updateRoute() {
const path = window.location.pathname;
const route = routes[path];
if (!route) {
return navigate('/login');
}
const template = document.getElementById(route.templateId);
const view = template.content.cloneNode(true);
const app = document.getElementById('app');
app.innerHTML = '';
app.appendChild(view);
}
نکات کلیدی برای یادآوری:
- بررسی وجود مسیر برای مسیر فعلی
- هدایت مجدد به صفحه ورود زمانی که مسیر نامعتبری وارد شود
- ارائه مکانیزم جایگزینی که از شکستن ناوبری جلوگیری میکند
- اطمینان از اینکه کاربران همیشه صفحهای معتبر میبینند حتی با URLهای نادرست
اگر مسیری پیدا نشود، حالا به صفحه login هدایت میشویم.
حالا بیایید تابعی بسازیم که هنگام کلیک روی لینک آدرس URL را بگیرد و رفتار پیشفرض مرورگر را جلوگیری کند:
function onLinkClick(event) {
event.preventDefault();
navigate(event.target.href);
}
توضیح این هندلر کلیک:
- جلوگیری از رفتار پیشفرض لینک مرورگر با استفاده از
preventDefault() - استخراج URL مقصد از المان لینک کلیک شده
- فراخوانی تابع ناوبری سفارشی به جای بارگذاری مجدد صفحه
- حفظ تجربه روان برنامه تک صفحهای
<a href="/dashboard" onclick="onLinkClick(event)">Login</a>
...
<a href="/login" onclick="onLinkClick(event)">Logout</a>
این اتصال رویداد onclick چه کاری انجام میدهد:
- اتصال هر لینک به سیستم ناوبری سفارشی ما
- تسلیم رویداد کلیک به تابع
onLinkClickبرای پردازش - فعالسازی ناوبری روان بدون بارگذاری صفحه
- حفظ ساختار درست URL که کاربران میتوانند آن را علامتگذاری یا به اشتراک بگذارند
ویژگی onclick رویداد click را به کد جاوااسکریپت، در اینجا فراخوانی تابع navigate()، متصل میکند.
تلاش کنید روی این لینکها کلیک کنید، حالا باید بتوانید بین صفحههای مختلف برنامه خود ناوبری کنید.
✅ متد history.pushState بخشی از استاندارد HTML5 است و در همه مرورگرهای مدرن پیادهسازی شده. اگر برنامه وبی برای مرورگرهای قدیمیتر میسازید، یک ترفند وجود دارد که میتوانید به جای این API استفاده کنید: با اضافه کردن هش (#) قبل از مسیر، میتوانید مسیریابیای پیادهسازی کنید که با ناوبری معمولی لینکهای anchor کار میکند و صفحه را بارگذاری مجدد نمیکند، چون هدفش ایجاد لینکهای داخلی در داخل صفحه بود.
فعال کردن دکمههای قبلی و بعدی
دکمههای «قبلی» و «بعدی» در مرور وب بنیادی هستند، درست مثل اینکه کنترلکنندههای ماموریت ناسا میتوانند وضعیتهای قبلی سیستم را در طول ماموریتهای فضایی مرور کنند. کاربران انتظار دارند این دکمهها کار کنند و وقتی کار نکنند، تجربه مرور مورد انتظار خراب میشود.
برنامه تک صفحهای ما به پیکربندی اضافی نیاز دارد تا این را پشتیبانی کند. مرورگر یک پشته تاریخچه حفظ میکند (که ما با history.pushState به آن اضافه کردهایم)، اما زمانی که کاربران در این تاریخچه ناوبری میکنند، برنامه ما باید با بهروزرسانی محتوای نمایش داده شده پاسخ دهد.
sequenceDiagram
participant User
participant Browser
participant App
participant Template
User->>Browser: کلیک روی لینک "ورود"
Browser->>App: رویداد onclick فعال شد
App->>App: اجرای preventDefault() و ناوبری به '/dashboard'
App->>Browser: history.pushState('/dashboard')
Browser->>Browser: بروزرسانی URL به /dashboard
App->>App: فراخوانی updateRoute()
App->>Template: یافتن و کپی قالب داشبورد
Template->>App: بازگردانی محتوای کپی شده
App->>Browser: جایگزینی محتوای برنامه با قالب
Browser->>User: نمایش صفحه داشبورد
Note over User,Template: کاربر دکمه بازگشت مرورگر را کلیک میکند
User->>Browser: کلیک روی دکمه بازگشت
Browser->>Browser: تاریخچه به /login بازگشت
Browser->>App: رویداد popstate فعال شد
App->>App: فراخوانی خودکار updateRoute()
App->>Template: یافتن و کپی قالب ورود
Template->>App: بازگردانی محتوای کپی شده
App->>Browser: جایگزینی محتوای برنامه با قالب
Browser->>User: نمایش صفحه ورود
نقاط کلیدی تعامل:
- عملکردهای کاربر با کلیکها یا دکمههای مرورگر ناوبری را فعال میکنند
- برنامه کلیک روی لینکها را رهگیری میکند تا از بارگذاری مجدد صفحه جلوگیری کند
- API تاریخچه تغییرات URL و پشته تاریخچه مرورگر را مدیریت میکند
- قالبها ساختار محتوا برای هر صفحه را فراهم میکنند
- گوشدهندههای رویداد اطمینان حاصل میکنند که برنامه به تمام انواع ناوبری پاسخ میدهد
استفاده از history.pushState ورودیهای جدیدی در تاریخچه ناوبری مرورگر ایجاد میکند. میتوانید این را با نگه داشتن دکمه بازگشت مرورگر خود امتحان کنید، باید چیزی شبیه این ببینید:
اگر چند بار روی دکمه برگشت کلیک کنید، میبینید که URL فعلی تغییر میکند و تاریخچه بهروزرسانی میشود، اما همان قالب نمایش داده میشود.
چون برنامه نمیداند که هر بار تاریخچه تغییر میکند باید تابع updateRoute() را فراخوانی کنیم. اگر به مستندات history.pushState نگاه کنید، میبینید که اگر حالت تغییر کند - یعنی به URL متفاوتی رفته باشیم - رویداد popstate فعال میشود. ما از این رویداد برای رفع این مشکل استفاده میکنیم.
کار
برای اطمینان از اینکه قالب نمایش داده شده هنگام تغییر تاریخچه مرورگر بهروزرسانی میشود، تابع جدیدی را ضمیمه میکنیم که updateRoute() را فراخوانی کند. این کار را در پایین فایل app.js انجام خواهیم داد:
window.onpopstate = () => updateRoute();
updateRoute();
درک این یکپارچگی تاریخچه:
- گوش دادن به رویدادهای
popstateکه هنگام ناوبری با دکمههای مرورگر رخ میدهد - استفاده از تابع پیکان برای نگارش کوتاه هندلر رویداد
- فراخوانی خودکار
updateRoute()هر زمان که حالت تاریخچه تغییر کند - راهاندازی برنامه با فراخوانی
updateRoute()هنگام بارگذاری اولیه صفحه - اطمینان از نمایش قالب صحیح بدون توجه به نحوه ناوبری کاربر
💡 نکته حرفهای: ما برای مختصر بودن این هندلر رویداد
popstateاز تابع پیکان استفاده کردیم، اما تابع معمولی هم همانطور کار میکرد.
این هم ویدئوی یادآوری درباره توابع پیکان:
🎥 برای دیدن ویدئو درباره توابع پیکان روی تصویر بالا کلیک کنید.
حالا سعی کنید از دکمههای قبلی و بعدی مرورگر خود استفاده کنید و بررسی کنید که مسیر نمایش داده شده این بار به درستی بهروزرسانی میشود.
⚡ کاری که میتوانید در ۵ دقیقه آینده انجام دهید
- ناوبری برنامه بانکی خود را با دکمههای عقب/جلو مرورگر تست کنید
- امتحان کنید URLهای مختلف را به صورت دستی در نوار آدرس وارد کنید تا مسیریابی را بسنجید
- ابزار توسعه مرورگر (DevTools) را باز کنید و ببینید قالبها چگونه در DOM کپی میشوند
- با اضافه کردن console.log جریان مسیریابی را دنبال کنید
🎯 اهدافی که در این ساعت میتوانید به آنها برسید
- آزمون پس از درس را کامل کنید و مفاهیم معماری SPA را درک کنید
- استایل CSS اضافه کنید تا قالبهای برنامه بانکی شما حرفهایتر به نظر برسند
- چالش صفحه خطای ۴۰۴ را با مدیریت مناسب خطا پیادهسازی کنید
- چالش صفحه اعتبارنامهها با قابلیتهای مسیریابی اضافی بسازید
- وضعیتهای بارگذاری و انتقالات بین تعویض قالبها را اضافه کنید
📅 برنامه هفتگی توسعه SPA شما
- برنامه بانکی کامل با فرمها، مدیریت داده و ماندگاری بسازید
- ویژگیهای پیشرفته مسیریابی مانند پارامتر مسیر و مسیرهای تو در تو اضافه کنید
- محافظهای ناوبری و مسیریابی مبتنی بر احراز هویت پیاده کنید
- کامپوننتهای قالب قابل استفاده مجدد و کتابخانه کامپوننت ایجاد کنید
- انیمیشنها و انتقال برای تجربه کاربری نرمتر اضافه کنید
- SPA خود را در یک پلتفرم میزبانی منتشر و مسیریابی را به درستی تنظیم کنید
🌟 تسلط ماهانه شما بر معماری فرانتاند
- SPAهای پیچیده با استفاده از فریمورکهای مدرن مثل React، Vue یا Angular بسازید
- الگوها و کتابخانههای پیشرفته مدیریت حالت را یاد بگیرید
- ابزارهای ساخت و جریانهای توسعه برای توسعه SPA را حرفهای کنید
- قابلیتهای برنامه وب پیشرونده و کارکرد آفلاین را پیاده کنید
- تکنیکهای بهینهسازی عملکرد برای SPAهای بزرگمقیاس مطالعه کنید
- در پروژههای متنباز SPA مشارکت کنید و دانش خود را به اشتراک بگذارید
🎯 جدول زمانی تسلط شما بر برنامه تک صفحهای
timeline
title پیشرفت یادگیری توسعه SPA و معماری مدرن وب
section پایهای (۲۰ دقیقه)
سیستمهای قالب: عناصر قالب HTML
: دستکاری DOM
: کلونسازی محتوا
: رندر داینامیک
section اصول مسیریابی (۳۰ دقیقه)
ناوبری سمت کلاینت: مدیریت URL
: API تاریخچه
: نگاشت مسیر
: رسیدگی به رویداد
section تجربه کاربری (۴۰ دقیقه)
واسط ناوبری: یکپارچگی مرورگر
: پشتیبانی دکمه بازگشت
: رسیدگی به خطا
: انتقالات نرم
section الگوهای معماری (۵۰ دقیقه)
SPAهای حرفهای: سیستمهای مؤلفه
: مدیریت وضعیت
: بهینهسازی عملکرد
: مرزهای خطا
section تکنیکهای پیشرفته (۱ هفته)
ادغام فریمورک: React Router
: Vue Router
: Angular Router
: کتابخانههای وضعیت
section مهارتهای تولید (۱ ماه)
توسعه سازمانی: سیستمهای ساخت
: راهبردهای تست
: خطوط استقرار
: پایش عملکرد
🛠️ خلاصه جعبه ابزار توسعه SPA شما
بعد از اتمام این درس، شما اکنون تسلط دارید بر:
- معماری قالب: کامپوننتهای HTML قابل استفاده دوباره با رندر محتوای داینامیک
- مسیریابی سمت کلاینت: مدیریت URL و ناوبری بدون بارگذاری مجدد صفحه
- یکپارچگی مرورگر: استفاده از History API و پشتیبانی از دکمههای عقب/جلو
- سیستمهای مبتنی بر رویداد: مدیریت ناوبری و تعامل با کاربر
- دستکاری DOM: کلون قالب، تعویض محتوا و مدیریت المانها
- مدیریت خطا: راهکارهای جایگزین مناسب برای مسیرهای نامعتبر و محتوای مفقود
- الگوهای عملکردی: بارگذاری کارآمد محتوا و استراتژیهای رندرینگ
کاربردهای دنیای واقعی: مهارتهای توسعه SPA شما مستقیماً در موارد زیر کاربرد دارد:
- برنامههای وب مدرن: توسعه با React، Vue، Angular و فریمورکهای دیگر
- برنامههای وب پیشرونده: برنامههایی با قابلیت کارکرد آفلاین و تجربه شبیه برنامه
- داشبوردهای سازمانی: برنامههای تجاری پیچیده با نماهای متعدد
- پلتفرمهای تجارت الکترونیک: کاتالوگ محصولات، سبد خرید و فرآیند پرداخت
- مدیریت محتوا: ایجاد و ویرایش محتوای داینامیک
- توسعه موبایل: برنامههای هیبریدی با استفاده از فناوریهای وب
مهارتهای حرفهای کسب شده: حالا شما میتوانید:
- معماری اپلیکیشنهای تکصفحهای با تفکیک مناسب دغدغهها
- پیادهسازی سیستمهای مسیریابی سمت کلاینت که با پیچیدگی برنامه مقیاسپذیر باشند
- اشکالزدایی جریانهای پیچیده ناوبری با استفاده از ابزارهای توسعهدهنده مرورگر
- بهینهسازی عملکرد برنامه از طریق مدیریت کارآمد قالبها
- طراحی تجربههای کاربری که حس بومی و پاسخگو داشته باشند
مفاهیم توسعه فرانتاند که تسلط یافتهاید:
- معماری کامپوننت: الگوهای رابط کاربری قابل استفاده مجدد و سیستمهای قالب
- همگامسازی وضعیت: مدیریت وضعیت URL و تاریخچه مرورگر
- برنامهنویسی مبتنی بر رویداد: مدیریت تعامل کاربر و ناوبری
- بهینهسازی عملکرد: دستکاری کارآمد DOM و بارگذاری محتوا
- طراحی تجربه کاربری: انتقالات نرم و ناوبری شهودی
سطح بعدی: آمادهاید تا چارچوبهای مدرن فرانتاند، مدیریت وضعیت پیشرفته یا ساخت برنامههای سازمانی پیچیده را کاوش کنید!
🌟 دستاورد کسب شده: شما بنیاد حرفهای اپلیکیشن تکصفحهای خود را با الگوهای معماری وب مدرن ساختهاید!
چالش GitHub Copilot Agent 🚀
از حالت Agent برای تکمیل چالش زیر استفاده کنید:
توضیح: برنامه بانکی را با پیادهسازی مدیریت خطا و قالب صفحه 404 برای مسیرهای نامعتبر بهبود دهید، تا تجربه کاربر هنگام رفتن به صفحات وجود نداشته بهبود یابد.
دستور: یک قالب HTML جدید با شناسه "not-found" ایجاد کنید که صفحه خطای 404 کاربر پسند با استایل نمایش دهد. سپس منطق مسیریابی جاوااسکریپت را تغییر دهید تا وقتی کاربران به URLهای نامعتبر میروند این قالب نشان داده شود، و یک دکمه "بازگشت به خانه" اضافه کنید که به صفحه ورود بازگردد.
برای اطلاعات بیشتر درباره حالت agent اینجا را ببینید.
🚀 چالش
یک قالب جدید و مسیر تازه برای صفحه سوم اضافه کنید که اعتبارهای این برنامه را نمایش دهد.
اهداف چالش:
- ایجاد قالب HTML جدید با ساختار محتوای متناسب
- افزودن مسیر جدید به شیء پیکربندی مسیرها
- شامل کردن لینکهای ناوبری به سمت و از صفحه اعتبارها
- آزمایش اینکه همه ناوبریها به درستی با تاریخچه مرورگر کار میکنند
آزمون پس از درس
مرور و خودآموزی
مسیریابی یکی از بخشهای بهطرز شگفتآوری پیچیده توسعه وب است، بهخصوص وقتی وب از رفتارهای تازهسازی صفحه معمول به تازهسازیهای صفحات اپلیکیشن تکصفحهای حرکت میکند. کمی درباره نحوه مدیریت مسیریابی در سرویس Azure Static Web App مطالعه کنید. آیا میتوانید توضیح دهید چرا برخی از تصمیمهای شرح دادهشده در آن سند ضروری هستند؟
منابع یادگیری اضافی:
- کاوش درباره اینکه چارچوبهای محبوبی مانند React Router و Vue Router چگونه مسیریابی سمت کلاینت را پیاده میکنند
- تحقیق در تفاوتهای مسیریابی بر اساس هش و مسیریابی API تاریخچه
- یادگیری درباره رندر سمت سرور (SSR) و تأثیر آن بر استراتژیهای مسیریابی
- بررسی اینکه برنامههای وب پیشرو (PWA) چگونه مسیریابی و ناوبری را مدیریت میکنند
تمرین
سلب مسئولیت: این سند با استفاده از سرویس ترجمه هوش مصنوعی Co-op Translator ترجمه شده است. در حالی که ما در تلاش برای دقت هستیم، لطفاً توجه داشته باشید که ترجمههای خودکار ممکن است حاوی اشتباهات یا نواقصی باشند. سند اصلی به زبان بومی خود باید به عنوان منبع معتبر در نظر گرفته شود. برای اطلاعات حساس، ترجمه حرفهای انسانی توصیه میشود. ما مسئول هیچگونه سوء تفاهم یا تفسیر نادرستی که از استفاده از این ترجمه ناشی شود، نیستیم.

