🔀

JavaScriptで学ぶ条件分岐と繰り返し処理:アコーディオンとタブパネルの実装を通じて

2025/03/09に公開

Webサイトを作っていると、「クリックしたら開閉する」「タブを切り替える」といった動きをつけたくなることがありますよね。このような動きを実現するためには、JavaScriptの条件分岐と繰り返し処理の理解が欠かせません。

この記事では、実際によく使われるUIコンポーネントの実装を通じて、JavaScriptの基本的な制御構文を学んでいきましょう。

目次

  1. 条件分岐とは
  2. 繰り返し処理とは
  3. 実装例1:アコーディオン
  4. 実装例2:タブパネル
  5. まとめ

1. 条件分岐とは

条件分岐は、「もし〜なら、こうする」というプログラムの流れを作るための制御構文です。例えば、「もし年齢が20歳以上なら、成人です」「もし年齢が20歳未満なら、未成年です」というような判断を行うことができます。

JavaScriptでは主にif文switch文を使用します。

if文の基本

if文は、最も基本的な条件分岐です。

// 年齢による判定の例
const age = 25;

if (age >= 20) {
    console.log('成人です');
} else {
    console.log('未成年です');
}
// 出力: 成人です

// 商品の在庫状態による表示の例
const stock = 3;

if (stock > 0) {
    console.log('在庫あり');
} else {
    console.log('在庫切れ');
}
// 出力: 在庫あり

if文の応用 - else if

複数の条件を順番に確認したい場合は、else ifを使います。

// 点数による成績判定の例
const score = 75;

if (score >= 90) {
    console.log('優');
} else if (score >= 70) {
    console.log('良');
} else if (score >= 50) {
    console.log('可');
} else {
    console.log('不可');
}
// 出力: 良

switch文の基本

switch文は、一つの変数に対して複数の値を比較する場合に便利です。if-elseが多数連なる場合の代替として使えます。

// 商品の状態による処理の例
const status = '発送準備中';

switch (status) {
    case '注文受付':
        console.log('注文を受け付けました');
        break; // breakがないと次のcaseも実行されてしまう
    case '発送準備中':
        console.log('商品の発送準備を行っています');
        break;
    case '発送完了':
        console.log('商品を発送しました');
        break;
    default: // どのcaseにも一致しない場合
        console.log('状態が不明です');
}
// 出力: 商品の発送準備を行っています

条件分岐での注意点

  • 条件式では==(等価演算子)と===(厳密等価演算子)の違いに注意
console.log(5 == '5');   // true - 型変換が行われる
console.log(5 === '5');  // false - 型も含めて比較
  • 複数の条件を組み合わせる場合は&&(AND)と||(OR)を使う
// 商品の在庫と会員ステータスによる表示の例
const stock = 3;
const isMember = true;

if (stock > 0 && isMember) {
    console.log('会員価格で購入できます');
}

2. 繰り返し処理とは

繰り返し処理は、同じような処理を複数回実行するための制御構文です。例えば、「商品一覧の各商品に『カートに入れる』ボタンを付ける」「すべての入力フォームをチェックする」といった処理に使います。

JavaScriptでは主にfor文forEachメソッドを使用します。

for文の基本

for文は、決まった回数の繰り返しや、カウンターが必要な場合に使います。

// 3回繰り返す例
for (let i = 0; i < 3; i++) {  // 初期値; 継続条件; 更新処理
    console.log(`${i + 1}回目の処理です`);
}
// 出力:
// 1回目の処理です
// 2回目の処理です
// 3回目の処理です

// 配列の要素を番号付きで表示する例
const fruits = ['りんご', 'バナナ', 'オレンジ'];
for (let i = 0; i < fruits.length; i++) {
    console.log(`${i + 1}番目の果物: ${fruits[i]}`);
}
// 出力:
// 1番目の果物: りんご
// 2番目の果物: バナナ
// 3番目の果物: オレンジ

forEachの基本

forEachは、配列の要素それぞれに対して処理を行う場合に使います。for文より記述が簡潔になります。

// 果物の一覧を表示する例
const fruits = ['りんご', 'バナナ', 'オレンジ'];
fruits.forEach((fruit) => {  // 各要素が順番にfruitに入る
    console.log(`この果物は${fruit}です`);
});
// 出力:
// この果物はりんごです
// この果物はバナナです
// この果物はオレンジです

// 商品の価格を表示する例
const products = [
    { name: 'コーヒー', price: 300 },
    { name: '紅茶', price: 400 },
    { name: 'お茶', price: 350 }
];
products.forEach((product) => {
    console.log(`${product.name}の価格は${product.price}円です`);
});
// 出力:
// コーヒーの価格は300円です
// 紅茶の価格は400円です
// お茶の価格は350円です

forEachの応用 - インデックスの取得

forEachでもインデックス(順番)を取得できます。

fruits.forEach((fruit, index) => {
    console.log(`${index + 1}番目の果物は${fruit}です`);
});
// 出力:
// 1番目の果物はりんごです
// 2番目の果物はバナナです
// 3番目の果物はオレンジです

繰り返し処理での注意点

  • 無限ループに注意(継続条件が常に真になる場合)
  • 配列の要素を操作する場合、元の配列が変更されることがある
  • 処理が重い場合はパフォーマンスに影響する

3. 実装例1:アコーディオン

アコーディオンとは、クリックすると内容が開閉するUIパーツです。クリックするたびに:

  • 閉じている場合は開く
  • 開いている場合は閉じる
    という動作を実現します。この「開いているか閉じているか」の状態判定に条件分岐を使用します。

HTML

<div class="accordion">
    <div class="accordion-item">
        <button class="accordion-header">よくある質問1:商品の返品について</button>
        <div class="accordion-content">
            <p>商品到着後7日以内であれば、返品を承ります。</p>
        </div>
    </div>
    <div class="accordion-item">
        <button class="accordion-header">よくある質問2:送料について</button>
        <div class="accordion-content">
            <p>5,000円以上のご購入で送料無料となります。</p>
        </div>
    </div>
</div>

CSS

.accordion-content {
    display: none;
    padding: 15px;
    background: #f5f5f5;
}

.accordion-content.active {
    display: block;
}

.accordion-header {
    width: 100%;
    padding: 10px;
    background: #e0e0e0;
    border: none;
    text-align: left;
    cursor: pointer;
}

JavaScript

// すべてのアコーディオンヘッダーに対して処理を設定
document.querySelectorAll('.accordion-header').forEach((header) => {
    // クリックされた時の処理を設定
    header.addEventListener('click', () => {
        // クリックされたヘッダーの次の要素(コンテンツ)を取得
        const content = header.nextElementSibling;

        // 条件分岐:コンテンツが表示されているかチェック
        if (content.classList.contains('active')) {
            // 表示されている場合は非表示に
            content.classList.remove('active');
        } else {
            // 非表示の場合は表示に
            content.classList.add('active');
        }
    });
});

ここでのポイント

  • nextElementSiblingは、要素の次の兄弟要素を取得するプロパティです
  • classList.contains()で要素がクラスを持っているかを確認しています
  • 条件分岐を使って表示状態に応じた処理を行っています

アコーディオン実装のよくある間違い

  • ヘッダーとコンテンツの関係が正しく取得できていない
// 間違い例
const content = document.querySelector('.accordion-content');  // 常に最初のコンテンツを取得してしまう
  • クラス名の指定ミス
// 間違い例
content.classList.remove('show');  // 'active'ではなく'show'を指定してしまっている
  • 複数のアコーディオンを同時に開けてしまう(要件によってはOK)

4. 実装例2:タブパネル

タブパネルとは、タブをクリックすることで異なるコンテンツを切り替えて表示するUIパーツです。

  • クリックされたタブをアクティブに
  • 他のタブを非アクティブに
  • クリックされたタブに対応するコンテンツを表示
    という一連の処理を実現します。これらの処理に繰り返し処理を使用します。

HTML

<div class="tab-container">
    <div class="tab-buttons">
        <button class="tab-button active" data-tab="1">商品情報</button>
        <button class="tab-button" data-tab="2">レビュー</button>
        <button class="tab-button" data-tab="3">お届けについて</button>
    </div>
    <div class="tab-contents">
        <div class="tab-content active" data-tab="1">
            <p>商品の詳細な情報を掲載しています。</p>
        </div>
        <div class="tab-content" data-tab="2">
            <p>実際に購入された方のレビューを掲載しています。</p>
        </div>
        <div class="tab-content" data-tab="3">
            <p>配送方法や納期について説明しています。</p>
        </div>
    </div>
</div>

CSS

.tab-content {
    display: none;
    padding: 20px;
    background: #f5f5f5;
}

.tab-content.active {
    display: block;
}

.tab-button {
    padding: 10px 20px;
    border: none;
    background: #f0f0f0;
    cursor: pointer;
}

.tab-button.active {
    background: #e0e0e0;
    font-weight: bold;
}

JavaScript

// すべてのタブボタンに対してイベントを設定
document.querySelectorAll('.tab-button').forEach((button) => {
    // クリックされた時の処理を設定
    button.addEventListener('click', () => {
        // クリックされたタブのIDを取得
        const tabId = button.dataset.tab;

        // ステップ1: すべてのタブボタンを非アクティブにする
        document.querySelectorAll('.tab-button').forEach((btn) => {
            btn.classList.remove('active');
        });

        // ステップ2: すべてのタブコンテンツを非表示にする
        document.querySelectorAll('.tab-content').forEach((content) => {
            content.classList.remove('active');
        });

        // ステップ3: クリックされたタブとそのコンテンツをアクティブにする
        button.classList.add('active');
        document.querySelector(`.tab-content[data-tab="${tabId}"]`).classList.add('active');
    });
});

ここでのポイント

  • dataset.tabでHTML要素のdata-tab属性の値を取得しています
  • 繰り返し処理を使って、すべてのタブとコンテンツを一度非表示にしています
  • 属性セレクター[data-tab="${tabId}"]で特定の要素を選択しています

タブパネル実装のよくある間違い

  • データ属性の取得ミス
// 間違い例
const tabId = button.getAttribute('data-tab');  // dataset.tabの方が簡潔
  • 対応するコンテンツが見つからない
// 間違い例
document.querySelector(`.content[data-tab="${tabId}"]`);  // クラス名が間違っている
  • イベントリスナーの重複登録
// 間違い例(イベント登録を繰り返し行ってしまう)
function initializeTabs() {
  document.querySelectorAll('.tab-button').forEach((button) => {
    button.addEventListener('click', handleTabClick);  // 毎回呼び出すと重複登録される
  });
}

5. まとめ

この記事では、実際のUIコンポーネント実装を通じて、JavaScriptの制御構文を学びました。

条件分岐の活用例

  • アコーディオンの開閉状態の判定(if文)
    • コンテンツが表示されているかどうかを判定
    • 状態に応じて表示/非表示を切り替え
  • 複数の状態を持つUIの制御(switch文)
    • 商品の状態や進行状況の管理
    • エラーメッセージの種類による表示の切り替え

繰り返し処理の活用例

  • 複数の要素への一括処理(forEach)
    • タブボタンへのイベント設定
    • クラスの一括削除
  • カウンターが必要な処理(for文)
    • 番号付きリストの作成
    • アニメーションの制御

これらの基本的な制御構文は、様々なUIコンポーネントの実装に応用できます。例えば:

  • モーダルウィンドウの表示制御
  • フォームのバリデーション
  • カルーセルスライダーの実装
    などにも同じような考え方で対応できるようになります。

参考文献

Discussion