コンテンツにスキップ

6. SFC 2

4 章では、コンポーネントの定義方法や props、式の表示などについて扱いました。本章では、Vue のコンポーネントにおける繰り返しや条件分岐の手法について述べていきます。

6.1 繰り返し

Vue では、繰り返しの手法を用いることによって同じコンポーネントを任意の数だけ表示させることができるようになります。次の例は、5 章で出てきた Names.vue の名前の表示方法を箇条書きに改善したプログラムです。

Names2.vue

<script setup lang="ts">
import { ref } from "vue";
const name = ref<string>("");
const names = ref<string[]>([]);
// ボタンがクリックされた時のイベントハンドラ
const onClickButton = () => {
names.value.push(name.value);
};
</script>
<template>
<div>
<input type="text" v-model="name" />
<button @click="onClickButton">名前を追加</button>
<ul>
<li v-for="(name, index) in names" :key="index">{{ name }}</li>
</ul>
</div>
</template>

このプログラムでは、names.join() によって行っていた処理が次のように変更されています。

<li v-for="(name, index) in names" :key="index">{{ name }}</li>

このように、繰り返したい要素に v-for ディレクティブを付けることで、配列の要素の数だけその要素を繰り返して表示することができます。書式は次の通りです。

<要素 v-for="(要素の変数, インデックス) in 配列" :key="キー">

インデックスが不要な場合は v-for="name in names" のように省略することもできます。また、配列の代わりに数値を渡す(v-for="i in 10")と、1 から 10 までの繰り返しになります。3 章の宣言型プログラミングの例で登場したのはこの形です1

また、繰り返される要素には :key 属性を渡す必要があります。key は繰り返される要素 1 つ 1 つを Vue が区別するための目印で、これがないと要素の追加・削除時に表示が崩れたり、無駄な再描画が発生したりすることがあります。通常、この値は繰り返しのインデックスを指定します(データが ID を持っているならその ID を渡します)。

6.2 演習 1

src/components/TwitterModoki.vue を作成して、次のようなコンポーネントを作成して下さい。ただし、今までに作成した TweetCreateTweet コンポーネントを使用して下さい(必要に応じて内容は修正して下さい)。

  1. CreateTweet コンポーネントにて文字が入力できるようになっている
  2. 「ツイート」ボタンを押すとツイート入力欄の下にツイートが表示される
  3. 画面イメージ
ヒント

今回の問題設定はやや難しめです。まず必要なものを整理してみます。

  1. 名前とツイート内容の組がセットになったデータを保持するための状態
  2. 「ツイート」ボタンがクリックされたとき用のイベントハンドラとなる関数
  3. 各ツイートのコンポーネントを包含するための要素

そして、おそらく 2 の関数が CreateTweet コンポーネントの @submit-tweet で受け取られるべきでしょう。2 のイベントハンドラの中では、引数として受け取ったデータを元に 1 の状態を更新する必要があります。また、Tweet には :name:text で props を渡します。

6.3 条件分岐

Vue では、状態や props の値に応じて表示するコンポーネントを出し分ける条件分岐のための仕組みがあります。次の例は、入力された値が 2 で割り切れるかどうかによって表示が切り替わるコンポーネントです。

IsEven.vue

<script setup lang="ts">
type Props = {
n: number;
};
defineProps<Props>();
</script>
<template>
<div>
<p v-if="n % 2 === 0">偶数</p>
<p v-else>奇数</p>
</div>
</template>

v-if に書いた条件式が真のときだけ、その要素が表示されます。直後の要素に v-else を付けると「そうでないとき」を表せます。3 つ以上に分岐したいときは v-else-if も使えます2

なお、v-elsev-if が付いた要素の直後の要素に付ける必要があります。間に別の要素を挟むことはできません。

6.4 演習 2

src/components/TwitterModoki.vue を修正して、投稿されたツイートがない時には「ツイートはありません」、そうでないときにはこれまで通りツイートが表示されるようにして下さい。

ヒント

ツイートの有無は、ツイートを保持する状態変数(おそらく配列だと思います)の長さをみることによって判断することができます。即ち、その長さが 0 であるかそうでないかによって条件分岐をすればいいでしょう。

1 つ注意点があります。v-elsev-for を同じ要素に付けることはできませんv-for の要素を <template v-else>...</template> というタグで囲むか、div などで囲むとうまくいきます。


Footnotes

  1. React では同じことを names.map((name, index) => <li key={index}>{name}</li>) のように、JavaScript の map 関数で書きます。Vue は専用の構文(ディレクティブ)を用意している、というアプローチの違いです。

  2. React では同じことを {n % 2 === 0 && <p>偶数</p>} のように論理演算子の短絡評価で書きます(React 編 6 章参照)。こちらも Vue は専用のディレクティブを用意しているわけです。