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/7-bank-project/1-template-route/README.md

21 KiB

ساخت اپلیکیشن بانکی قسمت اول: قالب‌های HTML و مسیرها در یک اپلیکیشن وب

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

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

مقدمه

از زمان ظهور جاوااسکریپت در مرورگرها، وب‌سایت‌ها تعاملی‌تر و پیچیده‌تر از همیشه شده‌اند. فناوری‌های وب اکنون به طور گسترده برای ایجاد اپلیکیشن‌های کاملاً کاربردی که مستقیماً در مرورگر اجرا می‌شوند، استفاده می‌شوند؛ چیزی که ما آن را اپلیکیشن‌های وب می‌نامیم. از آنجا که اپلیکیشن‌های وب بسیار تعاملی هستند، کاربران نمی‌خواهند برای هر بار انجام یک عمل، منتظر بارگذاری کامل صفحه باشند. به همین دلیل، جاوااسکریپت برای به‌روزرسانی مستقیم HTML با استفاده از DOM به کار می‌رود تا تجربه کاربری روان‌تری ارائه دهد.

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

پیش‌نیاز

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

قالب‌های HTML

اگر بخواهید چندین صفحه برای یک وب‌سایت ایجاد کنید، یک راه‌حل این است که برای هر صفحه‌ای که می‌خواهید نمایش دهید، یک فایل HTML جداگانه ایجاد کنید. اما این راه‌حل مشکلاتی دارد:

  • هنگام تغییر صفحه، باید کل HTML بارگذاری شود که ممکن است کند باشد.
  • اشتراک‌گذاری داده‌ها بین صفحات مختلف دشوار است.

یک روش دیگر این است که فقط یک فایل HTML داشته باشید و چندین قالب HTML با استفاده از عنصر <template> تعریف کنید. یک قالب، یک بلوک HTML قابل استفاده مجدد است که توسط مرورگر نمایش داده نمی‌شود و باید در زمان اجرا با استفاده از جاوااسکریپت ایجاد شود.

وظیفه

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

<div id="app">Loading...</div>

ما به آن یک id اختصاص می‌دهیم تا پیدا کردن آن با جاوااسکریپت آسان‌تر شود.

نکته: از آنجا که محتوای این عنصر جایگزین خواهد شد، می‌توانیم یک پیام یا نشانگر بارگذاری در آن قرار دهیم که هنگام بارگذاری اپلیکیشن نمایش داده شود.

سپس، قالب HTML برای صفحه ورود را زیر آن اضافه می‌کنیم. فعلاً فقط یک عنوان و یک بخش حاوی یک لینک که برای ناوبری استفاده خواهد شد، در آن قرار می‌دهیم.

<template id="login">
  <h1>Bank App</h1>
  <section>
    <a href="/dashboard">Login</a>
  </section>
</template>

بعد، یک قالب HTML دیگر برای صفحه داشبورد اضافه می‌کنیم. این صفحه شامل بخش‌های مختلفی خواهد بود:

  • یک هدر با عنوان و لینک خروج
  • موجودی فعلی حساب بانکی
  • لیستی از تراکنش‌ها که در یک جدول نمایش داده می‌شود
<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>

نکته: هنگام ایجاد قالب‌های HTML، اگر می‌خواهید ببینید چگونه به نظر می‌رسند، می‌توانید خطوط <template> و </template> را با قرار دادن آن‌ها در <!-- --> کامنت کنید.

چرا فکر می‌کنید از ویژگی‌های id در قالب‌ها استفاده می‌کنیم؟ آیا می‌توانیم از چیز دیگری مانند کلاس‌ها استفاده کنیم؟

نمایش قالب‌ها با جاوااسکریپت

اگر فایل HTML فعلی خود را در مرورگر امتحان کنید، خواهید دید که فقط پیام Loading... نمایش داده می‌شود. این به این دلیل است که ما باید کدی جاوااسکریپت اضافه کنیم تا قالب‌های HTML را ایجاد و نمایش دهد.

ایجاد یک قالب معمولاً در سه مرحله انجام می‌شود:

  1. پیدا کردن عنصر قالب در DOM، برای مثال با استفاده از document.getElementById.
  2. کپی کردن عنصر قالب، با استفاده از cloneNode.
  3. اتصال آن به DOM زیر یک عنصر قابل مشاهده، برای مثال با استفاده از appendChild.

چرا باید قالب را قبل از اتصال به DOM کپی کنیم؟ فکر می‌کنید اگر این مرحله را نادیده بگیریم چه اتفاقی می‌افتد؟

وظیفه

یک فایل جدید به نام app.js در پوشه پروژه خود ایجاد کنید و آن فایل را در بخش <head> فایل HTML خود وارد کنید:

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

حالا در 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) استفاده کنیم تا کل زیرشاخه قالب کپی شود.

حالا این تابع را با یکی از قالب‌ها فراخوانی کنید و نتیجه را مشاهده کنید.

updateRoute('login');

هدف این کد app.innerHTML = ''; چیست؟ بدون آن چه اتفاقی می‌افتد؟

ایجاد مسیرها

وقتی درباره یک اپلیکیشن وب صحبت می‌کنیم، منظور از مسیر، نقشه‌برداری 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' },
};

حالا کمی تابع updateRoute را تغییر می‌دهیم. به جای اینکه مستقیماً templateId را به عنوان آرگومان ارسال کنیم، می‌خواهیم ابتدا به URL فعلی نگاه کنیم و سپس از نقشه خود برای دریافت مقدار templateId مربوطه استفاده کنیم. می‌توانیم از 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 در مرورگر خود.

اگر یک مسیر ناشناخته در URL وارد کنید چه اتفاقی می‌افتد؟ چگونه می‌توانیم این مشکل را حل کنیم؟

افزودن ناوبری

مرحله بعدی برای اپلیکیشن ما افزودن امکان ناوبری بین صفحات بدون نیاز به تغییر دستی URL است. این شامل دو مورد می‌شود:

  1. به‌روزرسانی URL فعلی
  2. به‌روزرسانی قالب نمایش داده شده بر اساس URL جدید

ما قبلاً قسمت دوم را با تابع updateRoute انجام داده‌ایم، بنابراین باید بفهمیم چگونه URL فعلی را به‌روزرسانی کنیم.

ما باید از جاوااسکریپت و به طور خاص از history.pushState استفاده کنیم که اجازه می‌دهد URL را به‌روزرسانی کرده و یک ورودی جدید در تاریخچه مرور ایجاد کنیم، بدون اینکه HTML بارگذاری شود.

نکته: در حالی که عنصر HTML <a href> به تنهایی می‌تواند برای ایجاد لینک‌های هایپر به URLهای مختلف استفاده شود، به طور پیش‌فرض باعث بارگذاری مجدد HTML توسط مرورگر می‌شود. لازم است این رفتار را هنگام مدیریت مسیرها با جاوااسکریپت سفارشی، با استفاده از تابع preventDefault() در رویداد کلیک، جلوگیری کنیم.

وظیفه

بیایید یک تابع جدید ایجاد کنیم که بتوانیم برای ناوبری در اپلیکیشن خود استفاده کنیم:

function navigate(path) {
  window.history.pushState({}, path, path);
  updateRoute();
}

این روش ابتدا URL فعلی را بر اساس مسیر داده شده به‌روزرسانی می‌کند، سپس قالب را به‌روزرسانی می‌کند. ویژگی window.location.origin ریشه URL را بازمی‌گرداند و به ما اجازه می‌دهد یک URL کامل را از یک مسیر داده شده بازسازی کنیم.

حالا که این تابع را داریم، می‌توانیم مشکل مسیرهایی که با هیچ مسیر تعریف شده‌ای مطابقت ندارند، حل کنیم. تابع updateRoute را با افزودن یک حالت پیش‌فرض به یکی از مسیرهای موجود در صورت عدم یافتن مطابقت، تغییر خواهیم داد.

function updateRoute() {
  const path = window.location.pathname;
  const route = routes[path];

  if (!route) {
    return navigate('/login');
  }

  ...

اگر یک مسیر پیدا نشود، اکنون به صفحه login هدایت خواهیم شد.

حالا یک تابع برای دریافت URL هنگام کلیک روی یک لینک و جلوگیری از رفتار پیش‌فرض لینک مرورگر ایجاد کنیم:

function onLinkClick(event) {
  event.preventDefault();
  navigate(event.target.href);
}

سیستم ناوبری را با افزودن اتصال‌ها به لینک‌های Login و Logout در HTML کامل کنیم.

<a href="/dashboard" onclick="onLinkClick(event)">Login</a>
...
<a href="/login" onclick="onLinkClick(event)">Logout</a>

شیء event بالا، رویداد click را ضبط کرده و آن را به تابع onLinkClick ما ارسال می‌کند.

با استفاده از ویژگی onclick رویداد click را به کد جاوااسکریپت، در اینجا فراخوانی تابع navigate()، متصل کنید.

لینک‌ها را امتحان کنید، اکنون باید بتوانید بین صفحات مختلف اپلیکیشن خود ناوبری کنید.

روش history.pushState بخشی از استاندارد HTML5 است و در تمام مرورگرهای مدرن پیاده‌سازی شده است. اگر در حال ساخت یک اپلیکیشن وب برای مرورگرهای قدیمی هستید، یک ترفند که می‌توانید به جای این API استفاده کنید، استفاده از یک هش (#) قبل از مسیر است که می‌تواند مسیرهایی را پیاده‌سازی کند که با ناوبری معمولی لینک‌ها کار می‌کند و صفحه را بارگذاری نمی‌کند، زیرا هدف آن ایجاد لینک‌های داخلی در یک صفحه بوده است.

مدیریت دکمه‌های عقب و جلو مرورگر

استفاده از history.pushState ورودی‌های جدیدی در تاریخچه ناوبری مرورگر ایجاد می‌کند. می‌توانید با نگه داشتن دکمه عقب مرورگر خود بررسی کنید، باید چیزی شبیه به این نمایش دهد:

تصویر تاریخچه ناوبری

اگر چند بار روی دکمه عقب کلیک کنید، خواهید دید که URL فعلی تغییر می‌کند و تاریخچه به‌روزرسانی می‌شود، اما همان قالب همچنان نمایش داده می‌شود.

این به این دلیل است که اپلیکیشن نمی‌داند که باید هر بار که تاریخچه تغییر می‌کند، updateRoute() را فراخوانی کند. اگر به مستندات history.pushState نگاه کنید، می‌بینید که اگر حالت تغییر کند - به این معنی که به یک URL متفاوت منتقل شده‌ایم - رویداد popstate فعال می‌شود. ما از این رویداد برای رفع این مشکل استفاده خواهیم کرد.

وظیفه

برای اطمینان از اینکه قالب نمایش داده شده هنگام تغییر تاریخچه مرورگر به‌روزرسانی می‌شود، یک تابع جدید ایجاد می‌کنیم که updateRoute() را فراخوانی کند. این کار را در پایین فایل app.js خود انجام خواهیم داد:

window.onpopstate = () => updateRoute();
updateRoute();

نکته: ما از یک تابع فلش برای تعریف هندلر رویداد popstate خود استفاده کردیم تا کد مختصرتر باشد، اما یک تابع معمولی نیز به همان صورت کار می‌کند.

در اینجا یک ویدئو آموزشی درباره توابع فلش:

توابع فلش

🎥 روی تصویر بالا کلیک کنید تا ویدئویی درباره توابع فلش مشاهده کنید.

حالا دکمه‌های عقب و جلو مرورگر خود را امتحان کنید و بررسی کنید که مسیر نمایش داده شده این بار به درستی به‌روزرسانی می‌شود.


🚀 چالش

یک قالب و مسیر جدید برای صفحه سوم که اعتبار اپلیکیشن را نمایش می‌دهد، اضافه کنید.

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

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

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

مسیرها یکی از بخش‌های شگفت‌آوراً پیچیده توسعه وب هستند، به خصوص وقتی که وب از رفتارهای بارگذاری صفحه به رفتارهای بارگذاری صفحه در اپلیکیشن‌های تک صفحه‌ای حرکت می‌کند. کمی درباره چگونگی مدیریت مسیرها توسط سرویس Azure Static Web App بخوانید. آیا می‌توانید توضیح دهید چرا برخی از تصمیمات توضیح داده شده در آن سند ضروری هستند؟

تکلیف

بهبود مسیرها


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