تاروپود — خودآموز HTML و CSS

فصل ۷ از ۹

پیشرفت ترم
۰٪

ترم ۷ · پل به JavaScript

فهرست و حلقه

فصل ۷پیش‌نمایش رایگان
۸ دقیقه مطالعه فصل ۷

در این فصل چه می‌سازی#

تا امروز هر عنصرِ صفحه را خودت با دست می‌نوشتی؛ از این فصل، صفحه یاد می‌گیرد خودش را از روی داده بسازد. یک کارتِ «مهارت‌های من» می‌سازی که فهرستش از یک آرایهٔ JavaScript می‌آید: برای هر مهارت، کدِ تو یک <li> می‌سازد و به صفحه می‌چسباند. یک فرمِ کوچک هم دارد: هر مهارتِ تازه‌ای که تویش بنویسی، هم به آرایه اضافه می‌شود و هم بی‌درنگ روی صفحه ظاهر می‌شود.

یک ردیف کارت داده که با یک فلش چرخان یکی‌یکی به عنصرهای یک فهرست روی صفحهٔ وب تبدیل می‌شوند

آخر این فصل می‌توانی:

  • چند مقدار را با هم در یک array نگه داری و با index و length و push کار کنی
  • با for...offorEach) یک کار را برای تک‌تکِ عضوهای آرایه تکرار کنی
  • با createElement و append عنصرِ تازه در DOM بسازی
  • الگوی «اول خالی کن، بعد از نو بساز» را برای نمایشِ دوبارهٔ فهرست به‌کار ببری

قبل از شروع#

  • از فصل ۳: document.querySelector و textContent.
  • از فصل ۶: فرم در JavaScript — value، رویداد submit، preventDefault و if/else.
  • از فصل ۲: const و template literal.

مثل همیشه فقط یک مرورگر لازم داری، یا فقط همین آزمایشگاه.

۱. array: یک فهرست در یک متغیر#

این‌همه ترم گذشته و مهارت‌هایت دیگر در یک متغیر جا نمی‌شوند. let و const هر بار فقط یک مقدار نگه می‌داشتند؛ array یک ردیف مقدار را با هم نگه می‌دارد:

const skills = ['HTML', 'CSS', 'flexbox', 'grid'];

کروشه یعنی «این یک آرایه است» و عضوها با ویرگول جدا می‌شوند. برای آزمایش، این خط‌ها را در تبِ JS زیرِ آرایه بنویس و خروجی را با F12 در console ببین — از خودِ تبِ JS بنویس، نه با تایپ در console؛ خطِ فرمانِ console به صفحهٔ اصلی وصل است، نه به پیش‌نمایشِ آزمایشگاه:

  1. console.log(skills[0]) — جوابش 'HTML' است. به این شماره‌ها index می‌گویند و از صفر شروع می‌شوند.
  2. console.log(skills.length) — تعدادِ عضوها را می‌دهد.
  3. skills.push('JavaScript') و بعد console.log(skills) — یک عضو به تهِ آرایه اضافه شد.

Checkpoint. قبل از ادامه، جواب بده: اگر skills.length چهار باشد، آخرین عضو چه index ی دارد؟ (جواب: ۳ — چون شمارش از صفر شروع می‌شود.)

۲. for...of: برای هر عضو، یک بار#

آرایه بدونِ حلقه فقط یک انبار است. for...of یعنی «برای هر عضوِ این آرایه، این کار را بکن»:

for (const skill of skills) {
  console.log(skill);
}

مثل یک جمله بخوانش: «برای هر skill از skills…». داخلِ آکولاد، skill هر بار یکی از عضوهاست — بارِ اول 'HTML'، بارِ دوم 'CSS'، تا آخر. اگر آرایه خالی باشد، حلقه صفر بار اجرا می‌شود، بدونِ هیچ خطایی.

چک کن: در console، مهارت‌ها یکی‌یکی زیرِ هم چاپ می‌شوند.

۳. از آرایه تا صفحه: createElement و append#

querySelector فقط عنصرهای موجود را پیدا می‌کند؛ برای فهرستِ ما باید عنصرِ تازه ساخت. دستورش سه قدم دارد: بساز، پُر کن، بچسبان:

const list = document.querySelector('#skills-list');

for (const skill of skills) {
  const item = document.createElement('li');
  item.textContent = skill;
  list.append(item);
}

createElement('li') یک <li> می‌سازد که هنوز هیچ‌جای صفحه نیست — مثل آجری که هنوز در دیوار نگذاشته‌ای. textContent متنش را می‌گذارد و append آن را به تهِ عنصرِ list می‌چسباند؛ حالا واقعاً روی صفحه است.

چک کن: چهار مهارت زیرِ تیتر ظاهر شدند. حالا یک عضو به آرایه اضافه کن و ببین فهرست هم بلندتر می‌شود — صفحه دارد از روی داده ساخته می‌شود.

💡 نکته: «داده در آرایه، نمایش با حلقه» هستهٔ هر اپِ واقعی است: فیدِ هر شبکهٔ اجتماعی همین است — یک آرایهٔ پست، و حلقه‌ای که برای هرکدام یک کارت می‌سازد.

۴. دکمهٔ «افزودن» و باگِ فهرستِ دوقلو#

حالا فرم را زنده کنیم: مهارتِ تازه به آرایه push شود و فهرست دوباره ساخته شود. اولین تلاش — همان حلقه را داخلِ listener هم اجرا می‌کنیم:

const form = document.querySelector('#skill-form');
const input = document.querySelector('#skill-input');

form.addEventListener('submit', function (event) {
  event.preventDefault();
  skills.push(input.value);

  for (const skill of skills) {
    const item = document.createElement('li');
    item.textContent = skill;
    list.append(item);
  }
});

یک مهارت بنویس و «افزودن» را بزن. خرابی جلوی چشمت است: کلِ فهرست دوقلو شد — هر مهارتِ قدیمی حالا دو بار دیده می‌شود و با کلیکِ بعدی سه بار. چرا؟ چون append فقط اضافه می‌کند؛ <li> های قبلی سرِ جایشان‌اند و حلقه یک کپیِ کامل رویشان گذاشت.

شاید به سرت بزند کلِ کارت را خالی کنی و از نو بسازی: card.textContent = ''. امتحانش کنی، فاجعه می‌بینی: تیتر و فهرست و خودِ فرم همه محو می‌شوند — و listener فرم هم با فرم دفن می‌شود؛ صفحه دیگر حتی دکمه‌ای برای افزودن ندارد.

دو حالت از یک فهرست: یکی با عضوهای تکراری و دوقلوشده، دیگری درست و تک‌نسخه بعد از خالی‌شدن و ساختِ دوباره

⚠️ مواظب باش: گذاشتنِ textContent روی یک عنصر یعنی «همهٔ بچه‌هایش را دور بریز و فقط این متن را بگذار». فقط روی عنصری اجرایش کن که همهٔ محتوایش را خودِ حلقه‌ات می‌سازد — نه روی کارتی که فرم و دکمه‌ات هم تویش زندگی می‌کنند.

حالا که می‌دانی این چاقو کجا نباید برود، رفعِ باگ ساده است:

🔧 اگر کار نکرد: فهرست دوقلو شد؟ فقط خودِ فهرست را خالی کن، نه کارت را: قبل از حلقه بنویس list.textContent = '';. فهرست تنها چیزی است که حلقهٔ تو می‌سازد، پس خالی‌کردنش امن است.

نسخهٔ درست، با چکِ خالی‌نبودنِ ورودی (‏!== یعنی «مساوی نیست» — برعکسِ ===):

form.addEventListener('submit', function (event) {
  event.preventDefault();

  if (input.value !== '') {
    skills.push(input.value);
    input.value = '';

    /* aval list ra khali kon, bad hame ra az no besaz */
    list.textContent = '';
    for (const skill of skills) {
      const item = document.createElement('li');
      item.textContent = skill;
      list.append(item);
    }
  }
});

چک کن: هر مهارتِ تازه یک بار — و فقط یک بار — به تهِ فهرست اضافه می‌شود، و ورودیِ خالی هیچ کاری نمی‌کند.

۵. forEach: همان حلقه، به سبکِ خودِ آرایه#

آرایه‌ها راهِ دومی هم برای حلقه دارند: forEach. به آن یک function می‌دهی — همان جنسی که به addEventListener می‌دادی — و آرایه برای هر عضو یک بار صدایش می‌زند:

skills.forEach(function (skill) {
  console.log(skill);
});

نتیجه با for...of یکی است؛ فقط سبکِ نوشتن فرق دارد. هر دو را در کدِ دیگران خواهی دید، پس هر دو را بشناس — ما در این خودآموز for...of را ادامه می‌دهیم چون به جملهٔ آدمیزاد شبیه‌تر است.

🤖 با AI: حلقهٔ رندرِ خودت را به دستیار AI ات بده و بپرس: «این کد را خط‌به‌خط توضیح بده — و اگر وسطِ همین حلقه به skills عضوِ تازه push کنم چه می‌شود؟» جوابش را با چیزی که در آزمایشگاه می‌بینی چک کن؛ دستکاریِ آرایه وسطِ حلقه‌زدن روی همان آرایه، از آن جاهایی است که AI هم گاهی با اعتمادبه‌نفس اشتباه جواب می‌دهد.

کدِ کاملِ این فصل#

// script.js
const skills = ['HTML', 'CSS', 'flexbox', 'grid'];

const list = document.querySelector('#skills-list');

for (const skill of skills) {
  const item = document.createElement('li');
  item.textContent = skill;
  list.append(item);
}

const form = document.querySelector('#skill-form');
const input = document.querySelector('#skill-input');

form.addEventListener('submit', function (event) {
  event.preventDefault();

  if (input.value !== '') {
    skills.push(input.value);
    input.value = '';

    /* aval list ra khali kon, bad hame ra az no besaz */
    list.textContent = '';
    for (const skill of skills) {
      const item = document.createElement('li');
      item.textContent = skill;
      list.append(item);
    }
  }
});

و index.html:

<!-- index.html -->
<!DOCTYPE html>
<html lang="fa" dir="rtl">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>مهارت‌های من</title>
    <link rel="stylesheet" href="styles.css">
  </head>
  <body>
    <main class="card">
      <h1>مهارت‌های من</h1>
      <ul id="skills-list"></ul>
      <form id="skill-form">
        <label for="skill-input">مهارت جدید:</label>
        <input type="text" id="skill-input">
        <button type="submit">افزودن</button>
      </form>
    </main>
    <script src="script.js"></script>
  </body>
</html>

استایلِ کارت (styles.css) در آزمایشگاه از قبل آماده است — همه‌اش چیزهایی که خودت در ترم‌های CSS ساخته‌ای.

واژه‌های تازهٔ این فصل#

کلمه تلفظ به حروف فارسی یعنی چه
array اَرِی فهرستی از مقدارها در یک متغیر
index ایندکس شمارهٔ جای هر عضو؛ از صفر شروع می‌شود
push پوش افزودنِ یک عضو به تهِ آرایه
for...of فور آو حلقه روی تک‌تکِ عضوهای آرایه
forEach فور ایچ حلقهٔ خودِ آرایه که یک function می‌گیرد
createElement کریئیت اِلِمنت ساختنِ عنصرِ تازه که هنوز روی صفحه نیست
append اَپِند چسباندنِ عنصر به تهِ یک عنصرِ دیگر

تمرین‌ها

اول خودت فکر کن یا امتحان کن — بعد اینجا را باز کن.

در فصل بعد#

دادهٔ این فصل را خودت در کد نوشتی. فصل بعد داده از خودِ اینترنت می‌آید: با fetch از یک سرورِ واقعی دادهٔ زنده می‌گیریم — و مهم‌تر: یاد می‌گیری صفحه‌ای بسازی که وقتی شبکه قطع است هم آبرومند و سالم بماند.

به آخر این فصل رسیدی!

اگر ساختی و جواب داد، این دکمه مال توست.