はじめに
Vue.js を学習していて、動的コンポーネント(:is=""
)を活用して、タブ機能を作成してみました。
(Vue CLI を使用)
Vue CLI ディレクトリ構造

主要ファイルの記述
以下に主要ファイルのコードを記載する
- index.html
- main.js
- Tab1.vue
- Tab2.vue
- Tab3.vue
- App.vue
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>Vue.js タブ</title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
</body>
</html>
import Vue from 'vue';
import App from './App.vue';
new Vue({
render: h => h(App), // render関数にてApp.vueをレンダリング
}).$mount('#app') // index.htmlのid=appをマウント
App.vueの子コンポーネントファイルを3つ用意
<template>
<div>
<p>タブ1だよ</p>
</div>
</template>
<template>
<div>
<p>タブ2だよ</p>
</div>
</template>
<template>
<div>
<p>タブ3だよ</p>
</div>
</template>
上記3つの子コンポーネントの親コンポーネントファイルが App.vue
<template>
<div>
<ul class="tabs-menu">
<li
:class="{ active: currentTab === 'Tab1' }"
@click="currentTab = 'Tab1'"
>タブ1</li>
<li
:class="{ active: currentTab === 'Tab2' }"
@click="currentTab = 'Tab2'"
>タブ2</li>
<li
:class="{ active: currentTab === 'Tab3' }"
@click="currentTab = 'Tab3'"
>タブ3</li>
</ul>
<div class="tabs-content">
<component :is="currentTab"></component>
</div>
</div>
</template>
<script>
import Tab1 from "./components/Tab1.vue";
import Tab2 from "./components/Tab2.vue";
import Tab3 from "./components/Tab3.vue";
export default {
data() {
return {
currentTab: 'Tab1',
};
},
components: {
Tab1,
Tab2,
Tab3,
}
}
</script>
<style scoped>
body {
color: #3f4548;
}
/* ulのデフォルトスタイルを消去 */
.tabs-menu {
margin: 0;
padding: 0;
list-style-type: none;
}
/* タブの基本スタイル */
.tabs-menu li {
display: block;
float: left;
margin-right: 8px;
margin-bottom: -1px;
padding: 10px 20px;
border-style: solid;
border-width: 1px;
border-color: transparent;
border-radius: 4px 4px 0 0;
color: #557f95;
text-decoration: none;
}
/* タブにマウスを乗せたらカーソルの形を変える */
.tabs-menu li:hover {
cursor: pointer;
}
/* 非選択のタブにマウスを乗せたら色を変える */
.tabs-menu li:not(.active):hover {
border-color: #f0f0f0 #f0f0f0 #999;
background-color: #f0f0f0;
}
/* 選択中のタブ */
.tabs-menu .active {
border-color: #999 #999 transparent #999;
background-color: #f0fbff;
color: black;
}
/* タブコンテンツ表示エリア */
.tabs-content {
clear: both;
background-color: #f0fbff;
border: 1px solid #999;
border-radius: 0 4px 4px 4px;
padding: 10px 10px 30px 10px;
}
</style>
以下で App.vue について解説↓↓
App.vue について解説
子コンポーネントファイルを読み込み
<!-- 一部抜粋 -->
<script>
import Tab1 from "./components/Tab1.vue";
import Tab2 from "./components/Tab2.vue";
import Tab3 from "./components/Tab3.vue";
// 省略
</script>
コンポーネントをローカル登録
<!-- 一部抜粋 -->
<script>
components: {
Tab1,
Tab2,
Tab3,
}
}
</script>
表示タブの初期値はTab1に設定
<!-- 一部抜粋 -->
<script>
export default {
data() {
return {
currentTab: 'Tab1',
};
},
}
</script>
@click="currentTab = 'TabX'"
でタブをクリックすると currentTab
の値にコンポーネント名を代入する。
そして、<component :is="currentTab"></component>
のcurrentTab
に代入されている値によって表示するコンポーネントを判別させている。
:class="{ active: currentTab === 'Tab1' }"
はcurrentTab
がTab1
であればactive
クラスを付与している。
<template>
<div>
<ul class="tabs-menu">
<li
:class="{ active: currentTab === 'Tab1' }"
@click="currentTab = 'Tab1'"
>タブ1</li>
<li
:class="{ active: currentTab === 'Tab2' }"
@click="currentTab = 'Tab2'"
>タブ2</li>
<li
:class="{ active: currentTab === 'Tab3' }"
@click="currentTab = 'Tab3'"
>タブ3</li>
</ul>
<div class="tabs-content">
<component :is="currentTab"></component> <!-- ここで表示するコンポーネントを動的に切り替えている -->
</div>
</div>
</template>
最後に
<component :is="コンポーネント名"></component>
を使えば、v-if
v-show
を使わずに簡単に動的にコンポーネントの切り替えができた。
ご指摘などありましたら、お気軽にお願いします。
●参考リファレンス
Vue.js 動的 & 非動的コンポーネント