Skip to content

Tab 标签页 - Vant 4

Tab タブ 📑

紹介

🎯 Tab タブ はとても実用的なタブコンポーネントです。本の目次のように、異なるコンテンツ領域を簡単に切り替えられます。商品分類やニュースカテゴリ、設定ページの各オプションなど、UI を整然と保ち、優れた体験を提供します。

取り込み

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

js
import { createApp } from 'vue';
import { Tab, Tabs } from 'vant';

const app = createApp();
app.use(Tab);
app.use(Tabs);

コード例

基本的な使い方 🚀

最も簡単な使い方!v-model:active で現在のタブのインデックス/名前をバインドし、デフォルトでは最初のタブが有効です。まるで本をめくるように!

html
js
import { ref } from'vue'; exportdefault { setup() { const active = ref(0); return { active }; }, };

名前でマッチング 🏷️

より厳密に管理したい場合は、各タブに固有の name を指定しましょう。v-model:active の値はその name になり、読みやすくなります。

html
<van-tabs v-model:active="activeName">
  <van-tab title="タブ 1" name="a">コンテンツ 1</van-tab>
  <van-tab title="タブ 2" name="b">コンテンツ 2</van-tab>
  <van-tab title="タブ 3" name="c">コンテンツ 3</van-tab>
</van-tabs>
js
import { ref } from 'vue';

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

タブバーのスクロール 📱

タブが多すぎる場合は?心配無用!タブが 5 個を超えると自動的に横スクロールが有効になり、切り替え時には現在のタブを中央に表示します。

html
<van-tabs v-model:active="active">
  <van-tab v-for="index in 8" :title="`タブ ${index}`">
  コンテンツ {{ index }}
</van-tab>
</van-tabs>

タブの無効化 🚫

一部のタブを押せなくしたい場合は、disabled を設定して簡単に無効化できます。

html
<van-tabs v-model:active="active">
  <van-tab title="タブ 1">コンテンツ 1</van-tab>
<van-tab title="タブ 2" disabled>タブ 2</van-tab>
<van-tab title="タブ 3">コンテンツ 3</van-tab>
</van-tabs>

スタイル 🎨

Tab は柔軟に2種類のスタイルに対応:クラシックな line と、カード風の card。デフォルトは linetype で簡単に切り替え可能です。

html
<van-tabs v-model:active="active" type="card">
  <van-tab title="タブ 1">コンテンツ 1</van-tab>
<van-tab title="タブ 2">コンテンツ 2</van-tab>
<van-tab title="タブ 3">コンテンツ 3</van-tab>
</van-tabs>

クリックイベント 👆

ユーザーがどのタブをクリックしたかを知りたい?click-tab イベントが役立ちます。クリックごとに発火し、即応できます。

html
js
import { ref } from'vue'; import { showToast } from'vant'; exportdefault { setup() { const active = ref(0); constonClickTab = ({ title }) => showToast(title); return { active, onClickTab, }; }, };

スティッキー配置 📌

タブバーを常に視界に保ちたい?sticky を有効化しましょう。ページスクロール時に上部に「貼り付き」、いつでも切り替え可能です。

html
<van-tabs v-model:active="active" sticky>
  <van-tab title="タブ 1">コンテンツ 1</van-tab>
<van-tab title="タブ 2">コンテンツ 2</van-tab>
<van-tab title="タブ 3">コンテンツ 3</van-tab>
</van-tabs>

💡 ヒント: ページ上部に他の要素(ナビバーなど)がある場合は、offset-top で距離を調整して重なりを回避しましょう。

収縮レイアウト 📏

タブを幅いっぱいにしたくない場合は、shrink で収縮レイアウトを有効化。タブは左側へ揃って整然と並びます。

html
<van-tabs v-model:active="active" shrink>
  <van-tab title="タブ 1">コンテンツ 1</van-tab>
<van-tab title="タブ 2">コンテンツ 2</van-tab>
<van-tab title="タブ 3">コンテンツ 3</van-tab>
</van-tabs>

カスタムタイトル 🎭

タブを個性的にしたい?title スロットで完全にカスタマイズ可能。アイコンやバッジ、小さなアニメーションも追加できます。

html
<van-tabs v-model:active="active">
  <van-tab>
    <template #title>
      <van-icon name="more-o" />
      自定义
    </template>
    内容 1
  </van-tab>
  <van-tab title="标签 2">内容 2</van-tab>
</van-tabs>

切り替えアニメーション ✨

切り替えを滑らかにしたい?animated を有効化すると、ページをめくるような優雅なトランジションが有効になります。

html
<van-tabs v-model:active="active" animated>
  <van-tab title="タブ 1">コンテンツ 1</van-tab>
<van-tab title="タブ 2">コンテンツ 2</van-tab>
<van-tab title="タブ 3">コンテンツ 3</van-tab>
</van-tabs>

スワイプ切り替え 👈👉

より自然な操作感を求めるなら、swipeable を有効化。左右のスワイプでタブを切り替えられます。

html
<van-tabs v-model:active="active" swipeable>
  <van-tab title="タブ 1">コンテンツ 1</van-tab>
<van-tab title="タブ 2">コンテンツ 2</van-tab>
<van-tab title="タブ 3">コンテンツ 3</van-tab>
</van-tabs>

スクロールナビ 📜

長いコンテンツを表示する場合は、scrollspy を有効化。スクロール位置に応じて該当のタブが自動でハイライトされます。

html
<van-tabs v-model:active="active" scrollspy sticky>
  <van-tab title="タブ 1">コンテンツ 1</van-tab>
<van-tab title="タブ 2">コンテンツ 2</van-tab>
<van-tab title="タブ 3">コンテンツ 3</van-tab>
</van-tabs>

非同期切り替え ⏳

切り替え前にチェックや非同期処理が必要?before-change が役に立ちます。権限チェックや保存処理などを挟めます。

html
js
import { ref } from'vue'; exportdefault { setup() { const active = ref(0); constbeforeChange = (index) => { // 返回 false 表示阻止此次切换if (index === 1) { returnfalse; } // 返回 Promise 来执行异步逻辑returnnewPromise((resolve) => { // 在 resolve 函数中返回 true 或 falsesetTimeout(() =>resolve(index !== 3), 1000); }); }; return { beforeChange, }; }, };

Tips: ジェスチャーによるスワイプでは before-change は発火しません。

タイトルバーの非表示

showHeaderfalse に設定すると、タイトルバーをレンダリングしません。この場合、カスタムコンポーネントで active を制御できます。

html

API

Tabs Props

パラメータ説明タイプデフォルト値
v-model:active🎯 現在選択されているタブの識別子をバインドnumber | string0
type🎨 スタイルタイプ、オプション値は cardstringline
color🌈 タブのテーマカラーstring#1989fa
background🎭 タブバーの背景色stringwhite
duration⏱️ アニメーション時間、単位は秒、0を設定するとアニメーションを無効にするnumber | string0.3
line-width📏 下部バーの幅、デフォルト単位は pxnumber | string40px
line-height📐 下部バーの高さ、デフォルト単位は pxnumber | string3px
animated✨ タブコンテンツの切り替え時のトランジションアニメーションを有効にするかどうか(この属性を有効にすると、コンテンツエリアにスティッキーレイアウトがある場合、期待通りに動作しない)booleanfalse
border🖼️ タブバーの外枠を表示するかどうか、type="line" の時のみ有効booleanfalse
ellipsis✂️ 長すぎるタイトルテキストを省略するかどうか(shrinkfalse で、tab 数が swipe-threshold 以下の時のみ有効)booleantrue
sticky📌 スティッキーレイアウトを使用するかどうかbooleanfalse
shrink📏 左側収縮レイアウトを有効にするかどうかbooleanfalse
swipeable👈👉 スワイプによる左右切り替えを有効にするかどうか(この属性を有効にすると、コンテンツエリアにスティッキーレイアウトがある場合、期待通りに動作しない)booleanfalse
lazy-render🚀 遅延レンダリングを有効にするかどうか(初めてタブに切り替えた時にのみコンテンツレンダリングがトリガーされる)booleantrue
scrollspy📜 スクロールスパイモードを有効にするかどうかbooleanfalse
show-header v4.7.3👁️ タイトルバーを表示するかどうかbooleantrue
offset-top📍 スティッキーレイアウト時の上部との距離、px``vw``vh``rem 単位をサポート、デフォルトは pxnumber | string0
swipe-threshold🎚️ スクロールしきい値、タブ数がしきい値を超え、かつ総幅がタブバーの幅を超えると横スクロールを開始(shrinkfalse かつ ellipsistrue の時のみ有効)number | string5
title-active-color🎨 タイトルのアクティブ状態の色string-
title-inactive-color🎨 タイトルの非アクティブ状態の色string-
before-change⏳ タブ切り替え前のコールバック関数、false を返すと切り替えを阻止、Promise の返却をサポート(name: number | string) => boolean | Promise<boolean>-

Tab Props

パラメータ説明タイプデフォルト値
title📝 タイトルstring-
disabled🚫 タブを無効にするかどうかbooleanfalse
dot🔴 タイトルの右上に小さな赤い点を表示するかどうかbooleanfalse
badge🏷️ アイコンの右上のバッジのコンテンツ(dotfalse の時に有効)number | string-
name🏷️ タブ名、マッチングの識別子として使用number | stringタブのインデックス値
url🔗 クリック時に遷移するリンク先string-
to🧭 クリック時に遷移するルート先(Vue Router の to 相当)string | object-
replace🔄 遷移時に履歴を置換するかbooleanfalse
title-style🎨 自定义标题样式string | Array | object-
title-class🎭 自定义标题类名string | Array | object-
show-zero-badge0️⃣ バッジが 0 の場合に表示するかbooleantrue

Tabs Events

イベント名説明コールバック引数
click-tab👆 タブクリックで発火{ name: string | number, title: string, event: MouseEvent, disabled: boolean }
change🔄 アクティブタブが変化したとき発火name: string | number, title: string
rendered🎨 タブ内容が初回レンダリングされた時(遅延レンダリング時のみ)name: string | number, title: string
scroll📜 スクロール時に発火(sticky モード時のみ){ scrollTop: number, isFixed: boolean }

ヒント:clickdisabled イベントは廃止されました。click-tab を使用してください。

Tabs 方法

ref 経由で Tabs インスタンスを取得しメソッドを呼び出せます。詳細はコンポーネントのインスタンスメソッド を参照してください。

メソッド名説明引数戻り値
resize外側要素のサイズや表示状態が変化した際に再描画を行う--
scrollTo指定のタブへスクロール(スクロールナビモードで有効)*name: stringnumber*

类型定义

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

ts
importtype { TabProps, TabsType, TabsProps, TabsInstance } from'vant';

TabsInstance はコンポーネントインスタンスの型です:

ts
import { ref } from'vue'; importtype { TabsInstance } from'vant'; const tabsRef = ref<TabsInstance>(); tabsRef.value?.scrollTo(0);

Tabs Slots

名前説明
nav-leftタブバー左側の内容
nav-rightタブバー右側の内容
nav-bottomタブバー下部の内容

Tab Slots

名称说明
defaultタブ内容
titleカスタムタイトル

テーマカスタマイズ 🎨

スタイル変数

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

名称デフォルト説明
--van-tab-text-colorvar(--van-gray-7)📝 タブ文字色
--van-tab-active-text-colorvar(--van-text-color)✨ アクティブ時文字色
--van-tab-disabled-text-colorvar(--van-text-color-3)🚫 無効時文字色
--van-tab-font-sizevar(--van-font-size-md)📏 文字サイズ
--van-tab-line-heightvar(--van-line-height-md)📐 行の高さ
--van-tabs-default-colorvar(--van-primary-color)🎨 タブバーのデフォルト色
--van-tabs-line-height44px📏 タブバー高さ
--van-tabs-card-height30px🃏 カードスタイル高さ
--van-tabs-nav-backgroundvar(--van-background-2)🎭 背景色
--van-tabs-bottom-bar-width40px📏 ボトムバー幅
--van-tabs-bottom-bar-height3px📐 ボトムバー高さ
--van-tabs-bottom-bar-colorvar(--van-primary-color)🌈 ボトムバー色

よくある質問

非表示から表示に切り替えると、ボトムバー位置がずれる?

Tabs はマウント時に自身の幅を取得してボトムバー位置を計算します。最初に非表示の場合、幅が 0 となり位置計算ができません。

解決方法

方法1:表示制御に v-show を使っている場合は v-if に置き換えます。

html

方法2:コンポーネントの resize を呼び出して再描画します。

html
js
this.$refs.tabs.resize();

Tabs で swipeable や animated を有効化すると、内容領域の sticky が期待通りに動作しない

swipeable または animated を有効化すると、内容領域は transform を持つ要素でラップされます。この状態で sticky を使用すると、機能は有効でも表示位置がずれます。

例えば以下のケース:

html

これは、transform 要素内部の fixed が、その要素を基準に計算されるためです。

現在のコンポーネントがアクティブな Tab 内かどうかを判定する方法?

子コンポーネントで useTabStatususeAllTabStatus を呼び出すことで判定できます。

  • useTabStatus:現在の Tab がアクティブかどうか。Tab 外の場合は null
  • useAllTabStatus:ネストした Tab がある場合に、全ての上位 Tab がアクティブかどうか。Tab 外の場合は null
js
const isActive = useTabStatus(); 
// 嵌套 Tab 场景
const isAllActive = useAllTabStatus();

関連ドキュメント 📚

ナビゲーションコンポーネント 🧭

表示コンポーネント 📱

フィードバックコンポーネント 💬

ツールコンポーネント 🔧

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