概要
SPAにおいてタブメニューは割と使い場面が多いので、実装方法を忘れないようにメモします。
こういうやつ↓

実装
.vue
<div class="tab">
    <div class="tab_box container">
        <ul class="tab_list">
             <li @click="changeTab('1')" v-bind:class="{'active': isActive === '1'}">New</li>
             <li @click="changeTab('2')" v-bind:class="{'active': isActive === '2'}">Trend</li>
             <li @click="changeTab('3')" v-bind:class="{'active': isActive === '3'}">Items</li>
        </ul>
    </div>
</div>
<div class="container">
    <div class="article">
        <!--タブで入れ替えたいコンポーネントの配置-->
        <new-timeline v-show="isActive === '1'" class="item"></new-timeline>
        <trend-timeline v-show="isActive === '2'" class="item"></trend-timeline>
        <trend-item v-show="isActive === '3'"  class="item"></trend-item>
    </div>
</div>
<script>
import NewTimeline from './NewTimeline.vue'
import TrendItem from './TrendItem.vue'
import TrendTimeline from './TrendTimeline.vue'
export default {
    components: { NewTimeline, TrendTimeline, TrendItem },
    data() {
        return {
            isActive: '1',
        };
    },
    methods: {
        changeTab(val) {
            this.isActive = val;
        },
    },
}
</script>
<style scoped>
    .tab{
        width: 100%;
    }
    .tab_list {
        overflow: hidden;
        list-style: none;
    }
    .tab_list li {
        float: left;
        padding: 10px 20px;
        cursor: pointer;
        transition: .3s;
    }
    .tab_list li:not(:first-child) {
        border-left: none;
    }
    .tab_list li.active {
        border-bottom: 3px solid #000;
        cursor: auto;
    }
    .article{
        overflow: hidden;
        margin-top: -1px;
    }
</style>
ポイント
1.タブをクリックしたらchangeTabメソッドが発火する(このメソッドでは変数isActiveが変わるだけ)
2.isActiveの中身によってコンポーネントをv-showで入れ替える
3.v-bind:classでは動的にクラスを切り替えることができるので、isActiveの内容によって↓を発火させる
.tab_list li.active {
    border-bottom: 3px solid #000;
    cursor: auto;
}