Skip to content

Collapse 折りたたみパネル - Vant 4

📂 紹介

Collapse 折りたたみパネルは美しいアコーディオンのような本です 📖。各ページは豊富なコンテンツを提供し、軽くタップするだけで優雅に展開または折りたたむことができます。それはページ空間の魔法使いのようです ✨。複雑な情報をシンプルなタイトルの背後に巧妙に隠し、ユーザーは必要に応じて探索できます。インターフェイスの美しさと情報の完全な伝達を両立させます。FAQ、製品の詳細、設定オプションなど、折りたたみパネルはコンテンツの表示を整然とし、ユーザーに快適な閲覧体験を提供します。

📦 導入

以下の方法でグローバルにコンポーネントを登録します。詳細な登録方法についてはコンポーネントの登録を参照してください。

import { createApp } from 'vue'; import { Collapse, CollapseItem } from 'vant';

const app = createApp(); app.use(Collapse); app.use(CollapseItem);


## 🎯 コード例

### 基本的な使い方

`v-model` という親切な管理人 👨‍💼 を通じて、展開するパネルのリストを精確に制御します。`activeNames` 配列はVIPリストのように、どのパネルがその内容を表示する権利があるかを記録します。複数のパネルを同時に表示したいですか?問題ありません!この自由度によって、コンテンツの表示が思いのままになります。まるで交響楽団を指揮するかのように、各楽章を必要に応じて演奏できます。

```html
<van-collapse v-model="activeNames">
  <van-collapse-item title="タイトル1" name="1">
    コンテンツ1
  </van-collapse-item>
  <van-collapse-item title="タイトル2" name="2">
    コンテンツ2
  </van-collapse-item>
  <van-collapse-item title="タイトル3" name="3">
    コンテンツ3
  </van-collapse-item>
</van-collapse>

```js
import { ref } from 'vue';

export default {
  setup() {
    const activeNames = ref(['1']);
    return { activeNames };
  },
};

アコーディオン

accordion アコーディオンモードを有効にすると、優雅なピアニスト 🎹 のように、同じ時間に一つの美しいメロディに集中します。この時、activeName は文字列形式の独奏者に変身し、ステージには常に一つの主役だけが輝くことを確認します。この専門的な表示方法によって、ユーザーの注意力がより集中し、情報過多の問題を回避し、シンプルでありながら簡単ではない視覚体験を提供します。

html
<van-collapse v-model="activeName" accordion>
  <van-collapse-item title="タイトル1" name="1">
    コンテンツ1
  </van-collapse-item>
  <van-collapse-item title="タイトル2" name="2">
    コンテンツ2
  </van-collapse-item>
  <van-collapse-item title="タイトル3" name="3">
    コンテンツ3
  </van-collapse-item>
</van-collapse>

```js
import { ref } from 'vue';

export default {
  setup() {
    const activeName = ref('1');
    return { activeName };
  },
};

無効な状態

特定のパネルに disabled 属性を設定することで、「邪魔しないでください」という標識 🚫 をつけることができます。それらは存在感を維持しながら、誤ってトリガーされることもありません。この思いやりのある保護メカニズムによって、重要なコンテンツの安全性が確保されます。まるで貴重なアート作品に保護シールドを追加するようなものです。

html
<van-collapse v-model="activeNames">
  <van-collapse-item title="タイトル1" name="1">
    コンテンツ1
  </van-collapse-item>
  <van-collapse-item title="タイトル2" name="2" disabled>
    コンテンツ2
  </van-collapse-item>
  <van-collapse-item title="タイトル3" name="3">
    コンテンツ3
  </van-collapse-item>
</van-collapse>

### カスタムタイトルコンテンツ

`title` スロットというクリエイティブデザイナー 🎨 を通じて、タイトルバーに個性的な魂を注入することができます。単調なテキストに限定されず、アイコン、バッジ、アニメーション効果などを追加して、各パネルのタイトルを独特なアートワークにすることができます。ユーザーの目を引き、より豊富な情報を伝えます。

```html
<van-collapse v-model="activeNames">
  <van-collapse-item name="1">
    <template #title>
      <div class="custom-title">
        <span class="title-text">カスタムタイトル</span>
        <van-tag type="primary">NEW</van-tag>
      </div>
    </template>
    コンテンツ
  </van-collapse-item>
</van-collapse>

```js
import { ref } from 'vue';

export default {
  setup() {
    const activeNames = ref(['1']);
    return { activeNames };
  },
};

すべて展開とすべて切り替え

Collapse インスタンスの toggleAll という全能の指揮者 🎭 を通じて、すべてのパネルの集団パフォーマンスを一撃で実現できます。すべてのコンテンツを一見したいですか?それともシンプルな状態に戻したいですか?指揮棒を軽く振るだけで、すべてのパネルが整然とした協調性を見せながら、あなたの命令に応じます。まるで訓練された合唱団のように、完璧な調和を示します。

html
<van-collapse v-model="activeNames" ref="collapse">
  <van-collapse-item title="タイトル1" name="1">
    コンテンツ1
  </van-collapse-item>
  <van-collapse-item title="タイトル2" name="2">
    コンテンツ2
  </van-collapse-item>
  <van-collapse-item title="タイトル3" name="3">
    コンテンツ3
  </van-collapse-item>
</van-collapse>

<div class="demo-collapse-button">
  <van-button type="primary" @click="openAll">すべて展開</van-button>
  <van-button @click="toggleAll">すべて切り替え</van-button>
</div>

```js
import { ref } from 'vue';

export default {
  setup() {
    const activeNames = ref(['1']);
    const collapse = ref(null);
    
    const openAll = () => {
      collapse.value.toggleAll(true);
    };
    
    const toggleAll = () => {
      collapse.value.toggleAll();
    };
    
    return { activeNames, openAll, toggleAll, collapse };
  },
};

Tips: アコーディオンモードでは toggleAll メソッドを使用できません。

API

Collapse Props

パラメータ説明タイプデフォルト値
v-model現在展開中のパネルの名前アコーディオンモード:number | string非アコーディオンモード:(number | string)[]-
accordionアコーディオンモードを有効にするかどうかbooleanfalse
border外枠を表示するかどうかbooleantrue

Collapse Events

イベント名説明コールバックパラメータ
changeパネルを切り替えたときに発生activeNames: v-model にバインドされた値と同じ型

CollapseItem Props

パラメータ説明タイプデフォルト値
name一意の識別子、デフォルトはインデックス値number | stringindex
iconタイトルバー左側のアイコン名または画像リンク、Icon コンポーネントの name 属性 と同等string-

| size | タイトルバーのサイズ、large を選択可能 | string | - | | title | タイトルバー左側のコンテンツ | number | string | - | | value | タイトルバー右側のコンテンツ | number | string | - | | label | タイトルバーの説明情報 | number | string | - | | border | 内枠を表示するかどうか | boolean | true | | is-link | タイトルバー右側に矢印を表示し、クリックフィードバックを有効にするかどうか | boolean | true | | disabled | パネルを無効にするかどうか | boolean | false | | readonly | 読み取り専用モードかどうか、読み取り専用モードではパネルを操作できません | boolean | false | | lazy-render | 初めて展開する際にのみパネルのコンテンツをレンダリングするかどうか | boolean | true | | title-class | 左側のタイトルの追加クラス名 | string | - | | value-class | 右側のコンテンツの追加クラス名 | string | - | | label-class | 説明情報の追加クラス名 | string | - |

Collapse メソッド

ref を通じて CollapseItem インスタンスを取得し、インスタンスメソッドを呼び出すことができます。詳細についてはコンポーネントインスタンスメソッドを参照してください。

メソッド名説明パラメータ戻り値
toggleAllすべてのパネルの展開状態を切り替え、true を渡すとすべて展開、false を渡すとすべて折りたたみ、パラメータなしではすべて切り替えoptions?: boolean | object-

toggleAll メソッドの例

js
import { ref } from 'vue';
import type { CollapseInstance } from 'vant';

const collapseRef = ref<CollapseInstance>();

// すべて切り替え
collapseRef.value?.toggleAll();

// すべて展開
collapseRef.value?.toggleAll(true);

// すべて折りたたみ
collapseRef.value?.toggleAll(false);

// すべて切り替え、無効なパネルをスキップ
collapseRef.value?.toggleAll({
  skipDisabled: true,
});

// すべて展開、無効なパネルをスキップ
collapseRef.value?.toggleAll({
  expanded: true,
  skipDisabled: true,
});

CollapseItem メソッド

ref を通じて CollapseItem インスタンスを取得し、インスタンスメソッドを呼び出すことができます。詳細についてはコンポーネントインスタンスメソッドを参照してください。

メソッド名説明パラメータ戻り値
toggleパネルの展開状態を切り替え、true を渡すと展開、false を渡すと折りたたみ、パラメータなしでは切り替えexpand?: boolean-

型定義

コンポーネントは以下の型定義をエクスポートしています:

ts
import type {
  CollapseProps,
  CollapseItemProps,
  CollapseItemInstance,
  CollapseToggleAllOptions,
} from 'vant';

CollapseItemInstance はコンポーネントインスタンスの型で、次のように使用します:

ts
import { ref } from 'vue';
import type { CollapseItemInstance } from 'vant';

const collapseItemRef = ref<CollapseItemInstance>();
collapseItemRef.value?.toggle();

CollapseItem Slots

名前説明
defaultパネルのコンテンツ
titleカスタムタイトルバー左側のコンテンツ
valueカスタムタイトルバー右側のコンテンツ
labelカスタムタイトルバーの説明情報
iconカスタムタイトルバー左側のアイコン
right-iconカスタムタイトルバー右側のアイコン

テーマカスタマイズ

スタイル変数

コンポーネントは以下の CSS 変数を提供しており、カスタムスタイルに使用できます。使用方法については ConfigProvider コンポーネント を参照してください。

名前デフォルト値説明
--van-collapse-item-durationvar(--van-duration-base)-
--van-collapse-item-content-paddingvar(--van-padding-sm) var(--van-padding-md)-
--van-collapse-item-content-font-sizevar(--van-font-size-md)-
--van-collapse-item-content-line-height1.5-
--van-collapse-item-content-text-colorvar(--van-text-color-2)-
--van-collapse-item-content-backgroundvar(--van-background-2)-
--van-collapse-item-title-disabled-colorvar(--van-text-color-3)-

ベストプラクティス

コンテンツ組織戦略

折りたたみパネルのコンテンツ構造を合理的に組織しましょう 📋:

html
<!-- ✅ 推奨:論理的に明確なコンテンツグループ -->
<van-collapse v-model="activeNames">
  <van-collapse-item title="基本情報" name="basic">
    <div class="info-section">
      <p>名前:張三</p>
      <p>年齢:25歳</p>
      <p>職業:フロントエンドエンジニア</p>
    </div>
  </van-collapse-item>
  
  <van-collapse-item title="連絡先" name="contact">
    <div class="contact-section">
      <p>電話:138-0000-0000</p>
      <p>メール:zhangsan@example.com</p>
      <p>住所:北京市朝陽区</p>
    </div>
  </van-collapse-item>
  
  <van-collapse-item title="職歴" name="experience">
    <div class="experience-section">
      <!-- 詳細な職歴コンテンツ -->
    </div>
  </van-collapse-item>
</van-collapse>

<!-- ❌ 避ける:コンテンツが散らかったり集中しすぎたりする -->
<van-collapse v-model="activeNames">
  <van-collapse-item title="すべての情報" name="all">
    <!-- すべてのコンテンツを一つのパネルに詰め込む -->
  </van-collapse-item>
</van-collapse>

タイトル設計原則

html
<!-- ✅ 推奨:簡潔明確なタイトル -->
<van-collapse-item title="アカウント設定" name="account">
  <template #title>
    <div class="custom-title">
      <van-icon name="setting-o" />
      <span>アカウント設定</span>
      <van-tag type="primary" size="mini">重要</van-tag>
    </div>
  </template>
  <!-- コンテンツ -->
</van-collapse-item>

<!-- ❌ 避ける:タイトルが長すぎたり情報が明確でなかったりする -->
<van-collapse-item 
  title="これは非常に長いタイトルで、多くの不必要な説明情報が含まれています、ユーザーエクスペリエンスに影響します" 
  name="bad"
>
  <!-- コンテンツ -->
</van-collapse-item>

レスポンシブデザイン

html
<template>
  <van-collapse 
    v-model="activeNames" 
    :accordion="isMobile"
    :class="{ 'mobile-collapse': isMobile }"
  >
    <van-collapse-item 
      v-for="item in collapseItems" 
      :key="item.name"
      :title="item.title"
      :name="item.name"
    >
      <div :class="['content-wrapper', { 'mobile-content': isMobile }]">
        {{ item.content }}
      </div>
    </van-collapse-item>
  </van-collapse>
</template>

<script>
import { ref, computed, onMounted, onUnmounted } from 'vue';

export default {
  setup() {
    const screenWidth = ref(window.innerWidth);
    const activeNames = ref(['1']);
    
    const isMobile = computed(() => screenWidth.value < 768);
    
    const updateScreenWidth = () => {
      screenWidth.value = window.innerWidth;
    };
    
    onMounted(() => {
      window.addEventListener('resize', updateScreenWidth);
    });
    
    onUnmounted(() => {
      window.removeEventListener('resize', updateScreenWidth);
    });
    
    return { activeNames, isMobile };
  }
};
</script>

<style>
.mobile-collapse .van-collapse-item__title {
  font-size: 14px;
  padding: 12px 16px;
}

.mobile-content {
  padding: 12px 16px;
  font-size: 14px;
  line-height: 1.6;
}
</style>

パフォーマンス最適化のヒント

コンテンツの遅延読み込み

lazy-render 属性を利用してパフォーマンスを最適化しましょう 🚀:

html
<!-- ✅ 推奨:複雑なコンテンツには遅延読み込みを使用 -->
<van-collapse v-model="activeNames">
  <van-collapse-item 
    title="チャートデータ" 
    name="charts"
    :lazy-render="true"
  >
    <div v-if="activeNames.includes('charts')">
      <!-- 展開時のみ複雑なチャートコンポーネントをレンダリング -->
      <heavy-chart-component />
    </div>
  </van-collapse-item>
</van-collapse>

<!-- 動的にコンテンツを読み込む -->
<van-collapse-item 
  title="ユーザーリスト" 
  name="users"
  :lazy-render="true"
  @click="loadUserData"
>
  <div v-if="userDataLoaded">
    <user-list :data="userData" />
  </div>
  <van-loading v-else>読み込み中...</van-loading>
</van-collapse-item>

頻繁な再レンダリングを避ける

javascript
// ✅ 推奨:計算プロパティを使用してデータ処理を最適化
const processedItems = computed(() => {
  return rawItems.value.map(item => ({
    ...item,
    formattedDate: formatDate(item.date),
    isHighlighted: item.priority === 'high'
  }));
});

// ❌ 避ける:テンプレート内で複雑な計算を行う
// <van-collapse-item :title="formatComplexTitle(item)">

v-show と v-if を合理的に使用

html
<!-- 頻繁に切り替えるコンテンツには v-show を使用 -->
<van-collapse-item title="素早く切り替えるコンテンツ" name="quick">
  <div v-show="showQuickContent">
    <!-- 頻繁に表示/非表示にするコンテンツ -->
  </div>
</van-collapse-item>

<!-- 条件付きレンダリングには v-if を使用 -->
<van-collapse-item title="条件コンテンツ" name="conditional">
  <div v-if="shouldRenderContent">
    <!-- 条件によってレンダリングするかどうかを決めるコンテンツ -->
  </div>
</van-collapse-item>

デザインアドバイス

視覚階層

  • タイトル階層:重要性を区別するために異なるフォントサイズと色を使用 📊
  • コンテンツ間隔:一貫したパディングとマージンを維持 📏
  • アイコンの使用:認識性を高めるためにアイコンを合理的に使用 🎯
  • 状態フィードバック:明確な展開/折りたたみ状態の指示を提供 💫

インタラクション体験

  • アニメーション効果:スムーズな展開/折りたたみアニメーションを使用 🎬
  • タッチフレンドリー:モバイルデバイスで十分なタップ領域を確保 📱
  • キーボードナビゲーション:アクセシビリティを向上させるためにキーボード操作をサポート ⌨️
  • ローディング状態:非同期コンテンツにはローディングインジケータを提供 ⏳

よくある質問と解決策

Q: 折りたたみパネルのネストを実装するには?

html
<van-collapse v-model="parentActive">
  <van-collapse-item title="親パネル" name="parent">
    <van-collapse v-model="childActive" class="nested-collapse">
      <van-collapse-item title="子パネル 1" name="child1">
        <p>子コンテンツ 1</p>
      </van-collapse-item>
      <van-collapse-item title="子パネル 2" name="child2">
        <p>子コンテンツ 2</p>
      </van-collapse-item>
    </van-collapse>
  </van-collapse-item>
</van-collapse>

<style>
.nested-collapse {
  margin: 12px 0;
  border: 1px solid #ebedf0;
  border-radius: 6px;
}

.nested-collapse .van-collapse-item__title {
  background-color: #f7f8fa;
  font-size: 14px;
}
</style>

Q: 折りたたみパネルの検索フィルタを実装するには?

html
<template>
  <div>
    <van-search 
      v-model="searchKeyword" 
      placeholder="コンテンツを検索"
      @input="handleSearch"
    />
    
    <van-collapse v-model="activeNames">
      <van-collapse-item 
        v-for="item in filteredItems" 
        :key="item.name"
        :title="highlightTitle(item.title)"
        :name="item.name"
      >
        <div v-html="highlightContent(item.content)"></div>
      </van-collapse-item>
    </van-collapse>
    
    <van-empty 
      v-if="filteredItems.length === 0 && searchKeyword"
      description="関連コンテンツが見つかりません"
    />
  </div>
</template>

<script>
const searchKeyword = ref('');
const allItems = ref([
  { name: '1', title: 'ユーザー管理', content: 'システムユーザー情報を管理' },
  { name: '2', title: '権限設定', content: 'ユーザー権限と役割を設定' },
  { name: '3', title: 'データ統計', content: 'システムデータレポートを表示' }
]);

const filteredItems = computed(() => {
  if (!searchKeyword.value) return allItems.value;
  
  return allItems.value.filter(item => 
    item.title.includes(searchKeyword.value) || 
    item.content.includes(searchKeyword.value)
  );
});

const highlightTitle = (title) => {
  if (!searchKeyword.value) return title;
  return title.replace(
    new RegExp(searchKeyword.value, 'gi'),
    `<mark>$&</mark>`
  );
};

const highlightContent = (content) => {
  if (!searchKeyword.value) return content;
  return content.replace(
    new RegExp(searchKeyword.value, 'gi'),
    `<mark>$&</mark>`
  );
};
</script>

Q: 折りたたみパネルのドラッグソートを実装するには?

html
<template>
  <van-collapse v-model="activeNames">
    <draggable 
      v-model="sortableItems" 
      @end="handleDragEnd"
      item-key="name"
    >
      <template #item="{ element }">
        <van-collapse-item 
          :title="element.title"
          :name="element.name"
          class="draggable-item"
        >
          <template #title>
            <div class="drag-title">
              <van-icon name="bars" class="drag-handle" />
              <span>{{ element.title }}</span>
            </div>
          </template>
          {{ element.content }}
        </van-collapse-item>
      </template>
    </draggable>
  </van-collapse>
</template>

<script>
import draggable from 'vuedraggable';

const sortableItems = ref([
  { name: '1', title: 'プロジェクト 1', content: 'コンテンツ 1' },
  { name: '2', title: 'プロジェクト 2', content: 'コンテンツ 2' },
  { name: '3', title: 'プロジェクト 3', content: 'コンテンツ 3' }
]);

const handleDragEnd = (event) => {
  console.log('ドラッグ完了', event);
  // 新しい並び順をバックエンドに保存
  saveSortOrder(sortableItems.value);
};
</script>

<style>
.drag-title {
  display: flex;
  align-items: center;
  gap: 8px;
}

.drag-handle {
  cursor: move;
  color: #969799;
}

.draggable-item {
  transition: all 0.3s ease;
}

.draggable-item:hover {
  background-color: #f7f8fa;
}
</style>

高度な使い方の例

FAQ 質問応答システム

html
<template>
  <div class="faq-container">
    <van-search 
      v-model="searchQuery" 
      placeholder="よくある質問を検索"
      class="faq-search"
    />
    
    <div v-for="category in faqCategories" :key="category.id" class="faq-category">
      <h3 class="category-title">{{ category.name }}</h3>
      
      <van-collapse v-model="activeQuestions[category.id]">
        <van-collapse-item 
          v-for="faq in filteredFAQs(category.questions)"
          :key="faq.id"
          :name="faq.id"
          class="faq-item"
        >
          <template #title>
            <div class="faq-title">
              <van-icon name="help-o" />
              <span>{{ faq.question }}</span>
              <van-tag v-if="faq.isHot" type="danger" size="mini">人気</van-tag>
            </div>
          </template>
          
          <div class="faq-answer">
            <div v-html="faq.answer"></div>
            
            <div class="faq-actions">
              <van-button 
                size="mini" 
                type="primary" 
                plain
                @click="markHelpful(faq.id)"
              >
                役に立つ ({{ faq.helpfulCount }})
              </van-button>
              
              <van-button 
                size="mini" 
                plain
                @click="contactSupport"
              >
                サポートに問い合わせる
              </van-button>
            </div>
          </div>
        </van-collapse-item>
      </van-collapse>
    </div>
  </div>
</template>

製品仕様表示

html
<template>
  <div class="product-specs">
    <van-collapse v-model="activeSpecs" accordion>
      <van-collapse-item 
        v-for="spec in productSpecs"
        :key="spec.category"
        :name="spec.category"
        class="spec-item"
      >
        <template #title>
          <div class="spec-title">
            <van-icon :name="spec.icon" />
            <span>{{ spec.name }}</span>
            <van-badge 
              v-if="spec.highlight" 
              content="新"
              class="spec-badge"
            />
          </div>
        </template>
        
        <div class="spec-content">
          <div 
            v-for="detail in spec.details"
            :key="detail.key"
            class="spec-detail"
          >
            <span class="detail-label">{{ detail.label }}:</span>
            <span class="detail-value">{{ detail.value }}</span>
          </div>
          
          <div v-if="spec.comparison" class="spec-comparison">
            <h4>同種製品との比較</h4>
            <van-grid :column-num="3" :border="false">
              <van-grid-item 
                v-for="item in spec.comparison"
                :key="item.name"
                :text="item.name"
                :badge="item.advantage ? '利点' : ''"
              />
            </van-grid>
          </div>
        </div>
      </van-collapse-item>
    </van-collapse>
  </div>
</template>

関連コンポーネント

関連リンク

Vant に基づく企業向けモバイルソリューション