🦒 Vue3 タブUI
作成日: 2024/04/12
0

今回はcomposition APIでタブ機能を作った。

親でコンテンツをいくつ入れるかできるので子コンポーネントは使い回しが出来て便利だと思う。

子コンポーネント

まずはタブの数分、繰り返し表示したいのでv-forを使い、クリックされたタブのidと内容(text)を取得するためにv-on:clickを設定しタブナンバーの中身を引数に渡す。
クリックされたクラスをisActiveを付与したいので===タブ.id
*liタグの中身.numberは別になんでもいい
タブで押された内容を下のタブに表示するため、isActiveで判断しデフォルト(最初に表示する文)とそれ以外を入れるためにv-elseを設定する。

<template>
  <!-- タブ -->
  <ul>
    <li v-for="△△△ in ○○○" :key="△△△.id" @click="関数名(△△△.id,△△△.text)" :class="{ 'isActive': isActive === △△△.id }">{{△△△.number}}</li>
  </ul>
    <!-- 押されたタブの中身 -->
    <ul>
     <li v-if="isActive === '1'">{{ defoText }}</li>
     <li v-else>{{ isText }}</li>
  </ul>
</template>

次に、jsの設定。
○○○の部分は親コンポーネントから設定するのでprops
クリック関数でpropsで渡ってきた○○○を△△△に分け、idとtextを引数に渡し、クリックされたタブのid(numberでもいい)をisActiveに代入し、isTextの中身も代入する
クリックされる前(最初の表示)でisActiveの初期値などを設定する

<script setup lang="ts">
import { ref,defineProps } from "vue";
const isActive = ref("1") //初期値を1に設定
const isText = ref("") //初期値を空文字にする

defineProps({
  ○○○: Array, //配列の中にobjだが、渡ってくるのは一番外の配列になるため
    defoText: String,
})

const 関数名 = function(num:string,txt:string):void{
  //引数にliがクリックされた時に渡ってくる物を入れる
    isActive.value = num;
  isText.value = txt;
}
</script>

親コンポーネント

importで読み込み、タグを入れる(省略)
タブの中身や個数をオブジェクトに設定する

<template>
  <コンポーネント名 :○○○="tab" :defoText="defoText">
</template>
<script setup lang="ts">
// interfaceを決める
interface tabinter{
  number: Number,
  id: String,
  text: String,
}
// タブを作る
const tab:tabinter[] = [
  {number: 1, id: "1", text: "このコンテンツは1です"},
  {number: 2, id: "2", text: "このコンテンツは2です"},
]
// デフォルト文字を取得するためfind関数を使う
const itemTxt = tab.find((tabitem):boolean => tabitem.id === '1')//findはture or falceを返すのでboolean
const tabfirst = itemTxt?.text;
const defoText = ref(tabfirst)
</script>

完成系

//子コンポーネント
<template>
  <ul class="tabs">
    <li v-for="something in somethingList" :key="something.id" @click="change(something.id,something.text)" :class="{ 'isActive': isActive === something.id}">
      タブ{{ something.number }}
    </li>
  </ul>

  <!-- 親から子へ -->
  <ul class="contents">
    <li v-if="isActive === '1'">{{ defoText }}</li>
    <li v-else>{{ isText }}</li>
  </ul>
</template>
<script setup lang="ts">
import { ref, defineProps } from 'vue';
const isActive = ref("1");
const isText = ref("");

const change = function(num:string,txt:string):void {
  isActive.value = num;
  isText.value = txt;
}
defineProps({
  somethingList: Array,
  defoText: String
})
</script>
// 親コンポーネント
<template>
  <NewList :somethingList="tab" :defoText="defoText"></NewList>
</template>
<script setup lang="ts">
import { ref } from 'vue';
// tab interface
interface tabinter {
  number: Number,
  id: String,
  text: String,
}
// tab
const tab:tabinter[] = [
  {number: 1, id: "1", text: "このコンテンツは1です"},
  {number: 2, id: "2", text: "このコンテンツは2です"},
  {number: 3, id: "3", text: "このコンテンツは3です"},
  {number: 4, id: "4", text: "このコンテンツは4です"},
  {number: 5, id: "5", text: "このコンテンツは5です"},
  {number: 6, id: "6", text: "このコンテンツは99です"},
]
const itemTxt = tab.find((tabitem):boolean => tabitem.id === '1')
const tabfirst = itemTxt?.text;
const defoText = ref(tabfirst)
<script>

フロントエンドエンジニアを頑張って勉強中。 最近はVueやNuxtを勉強中です。 コミュニティなどあれば参加してみたいと思ってます。 どうぞ、生暖かい目で見ていただけると幸いです。