【Vue】テンプレート構文の基本:Mustache構文とディレクティブ

JavaScript

こんにちは、かつコーチです。

前回はViteでVueの開発環境を作りました。

今回は、.vueファイルの<template>部分に書く、Vue独自のテンプレート構文を解説していきます。

ここを押さえると、Vueらしいコードがぐっと読み書きしやすくなります。

テンプレート構文とは?

HTMLに近い書き方でUIを組み立てる

テンプレート構文とは、<template>タグの中に、通常のHTMLに近い書き方でUIを組み立てる、Vue独自の記法のことです。

<script setup lang="ts">
const message = "こんにちは、かつコーチです!";
</script>

<template>
  <p>{{ message }}</p>
</template>

<script setup lang="ts">の中で定義した変数を、<template>の中でそのまま使える点が最大の特徴です。

Reactの場合、JSXの中に{変数名}と書いてJavaScriptの値を埋め込みますが、Vueでは{{ }}という書き方をします。

なぜHTMLに近い書き方ができるのか

VueのテンプレートはコンパイルされてJavaScriptの描画処理に変換されますが、見た目上はHTMLの延長として書けるように設計されています。

これにより、HTML・CSSの知識がある人であれば、JSXよりも直感的にUIのコードを読めることが多いです。

私自身、初めてVueのテンプレートを見たときに「これ、ほぼHTMLじゃん」と感じて、心理的なハードルがぐっと下がったのを覚えています。

Mustache構文:{{ }}で値を表示する

基本の書き方

変数の値をテンプレート内に表示するには、{{ }}(二重波括弧)で囲みます。

この書き方をMustache構文(口ひげのような見た目から名付けられた)と呼びます。

<script setup lang="ts">
const userName = "かつコーチ";
const age = 30;
</script>

<template>
  <p>名前:{{ userName }}</p>
  <p>年齢:{{ age }}歳</p>
</template>

{{ }}の中には、単純な変数だけでなく、簡単な式も書けます。

<script setup lang="ts">
const price = 1000;
</script>

<template>
  <p>税込価格:{{ price * 1.1 }}円</p>
</template>

ただし、{{ }}の中に書けるのは1行で完結する簡単な式までです。

複雑な計算や条件分岐は、後の記事で扱う算出プロパティ(computed)にまとめるのがVueの基本的な作法です。

ディレクティブ:HTMLタグに機能を追加する

ディレクティブとは

ディレクティブとは、HTMLタグにv-から始まる特別な属性を追加することで、Vueに特別な振る舞いを指示する仕組みです。

代表的なディレクティブを見ていきましょう。

v-bind:属性に変数を渡す

HTML属性の値に変数を渡したいときは、v-bindを使います。

<script setup lang="ts">
const imageUrl = "/images/profile.png";
const isDisabled = true;
</script>

<template>
  <img v-bind:src="imageUrl" alt="プロフィール画像" />
  <button v-bind:disabled="isDisabled">送信</button>
</template>

v-bind:属性名という書き方をよく使うため、:属性名という省略記法も用意されています。

<template>
  <img :src="imageUrl" alt="プロフィール画像" />
</template>

実務では、この省略記法の方が圧倒的によく使われます。

v-if / v-show:条件によって表示を切り替える

条件によって要素の表示・非表示を切り替えたいときは、v-ifまたはv-showを使います。

<script setup lang="ts">
const isLoggedIn = true;
</script>

<template>
  <p v-if="isLoggedIn">ログイン中です</p>
  <p v-else>ログインしてください</p>
</template>

Reactでは{isLoggedIn && <p>ログイン中です</p>}のように、JavaScriptの論理演算子で条件分岐を表現していましたが、Vueではv-ifv-elseという専用のディレクティブで表現します。

v-ifは条件がfalseのときDOM自体を作らないのに対し、v-showdisplay: noneでCSS上だけ非表示にする、という違いがあります。

頻繁に表示・非表示を切り替える要素にはv-show、めったに切り替わらない要素にはv-ifを使う、という使い分けが基本です。

v-for:リストを繰り返し表示する

配列のデータを一覧表示したいときは、v-forを使います。

<script setup lang="ts">
const todos = ["買い物に行く", "ブログを書く", "運動する"];
</script>

<template>
  <ul>
    <li v-for="(todo, index) in todos" :key="index">{{ todo }}</li>
  </ul>
</template>

Reactのtodos.map((todo, index) => <li key={index}>{todo}</li>)と同じ役割です。

:key(Reactでいうkeyprops)を必ず指定して、各要素を一意に識別できるようにするのは、Reactと同じく重要なルールです。

つまずきやすいポイント:v-forとv-ifの同時使用

意図しない挙動になりやすい組み合わせ

私が実際につまずいた経験として、リストの中で条件付き表示をしたいときに、v-forv-ifを同じ要素に書いてしまい、想定と違う挙動になったことがあります。

❌ Before:同じ要素にv-forv-ifを両方書く

<script setup lang="ts">
type Todo = { id: number; title: string; completed: boolean };

const todos: Todo[] = [
  { id: 1, title: "買い物に行く", completed: false },
  { id: 2, title: "ブログを書く", completed: true },
];
</script>

<template>
  <ul>
    <!-- 未完了のTODOだけ表示したいつもりが… -->
    <li v-for="todo in todos" v-if="!todo.completed" :key="todo.id">
      {{ todo.title }}
    </li>
  </ul>
</template>

Vue3ではv-ifの方がv-forより優先度が高く評価されるため、todoという変数がまだ定義されていない状態でv-ifが評価され、エラーになったり意図しない結果になったりします。

✅ After:<template>タグで分けるか、事前にフィルタしておく

<script setup lang="ts">
import { computed } from "vue";

type Todo = { id: number; title: string; completed: boolean };

const todos: Todo[] = [
  { id: 1, title: "買い物に行く", completed: false },
  { id: 2, title: "ブログを書く", completed: true },
];

// あらかじめ未完了のTODOだけに絞り込んでおく
const incompleteTodos = computed(() => todos.filter((todo) => !todo.completed));
</script>

<template>
  <ul>
    <li v-for="todo in incompleteTodos" :key="todo.id">
      {{ todo.title }}
    </li>
  </ul>
</template>

Vue公式ドキュメントでも、v-forv-ifを同じ要素に併用しないことが明確に推奨されています。

「表示するデータを絞り込む処理」と「絞り込んだデータを繰り返し表示する処理」を分けて考える癖をつけると、このつまずきを防げます。

computedについては、次々回の記事で詳しく解説します。

まとめ

この記事のポイント

  • {{ }}(Mustache構文)で、変数や簡単な式をテンプレートに表示できる
  • v-bind(省略形:)で、HTML属性に変数を渡せる
  • v-if / v-showで条件による表示切り替え、v-forでリストの繰り返し表示ができる
  • v-ifv-showは、DOMごと消すか見た目だけ隠すかという役割が異なる
  • v-forv-ifは同じ要素に併用せず、computedなどで事前に絞り込んでおくのが安全

次に読むべき記事

Reactの経験がある方は、「JSXではこう書いていたのに」という部分が色々気になってきた頃だと思います。

次回は、ReactとVueの記法をまとめて対応表として整理していきます。

→ 次の記事:Reactを知っている人向け:ReactとVueの記法対応表

タイトルとURLをコピーしました