テンプレート構文 ≒ HTML
テンプレートは HTML である
Vue.js のテンプレート構文を学ぶにあたって,最も重要なことを先に言います.
Vue のテンプレートは,valid な HTML です.
JSX のように JavaScript の中に HTML を書くのではありません.
HTML の中に,ほんの少しだけ Vue 固有の属性を足すだけです.
ブラウザの HTML パーサーがそのまま解釈できる,正当な HTML です.
これは Vue の設計思想の根幹にある考え方です.
Mustache 構文: {{ }}
データをテンプレートに表示するには {{ }} (Mustache 構文) を使います.
まずは一番シンプルな例から.
<div id="app">
<h1>{{ message }}</h1>
</div>
<script type="importmap">
{ "imports": { "vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.js" } }
</script>
<script type="module">
import { createApp, ref } from 'vue'
createApp({
setup() {
const message = ref('My Bookshelf')
return { message }
}
}).mount('#app')
</script>
{{ message }} の部分が setup() で定義した message の値に置き換わります.
テンプレートの残りは ただの HTML のままです.
v-for: 繰り返し
HTML をコピペする代わりに,配列からリストを生成します.
<div id="app">
<h1>My Bookshelf</h1>
<p>最近読んだ本の記録です.</p>
<div class="card" v-for="book in books">
<h2>{{ book.title }}</h2>
<p>{{ book.description }}</p>
<span class="tag" v-for="tag in book.tags">
{{ tag }}
</span>
</div>
</div>
v-for="book in books" — これが Vue のディレクティブです.
HTML の属性として書きます.class や id を書くのと同じ場所に書きます.
ここで注目すべきは,テンプレートの構造が前章の静的 HTML とほぼ同じ だということです.
| 静的 HTML | Vue テンプレート |
|---|---|
<div class="card"> |
<div class="card" v-for="book in books"> |
<h2>リーダブルコード</h2> |
<h2>{{ book.title }}</h2> |
<span class="tag">programming</span> |
<span class="tag" v-for="tag in book.tags">{{ tag }}</span> |
HTML の構造はそのまま.属性が一つ増えて,テキストが {{ }} になっただけ.
これがテンプレート DSL (Domain Specific Language) です.HTML を壊さず,拡張しています.
v-bind: 属性のバインディング
テキストコンテンツだけでなく,HTML 属性にもデータを反映できます.
<a v-bind:href="book.url">{{ book.title }}</a>
省略記法として : だけで書くこともできます.
<a :href="book.url">{{ book.title }}</a>
これも HTML の属性 の位置に書いています.
特殊な構文ではなく,HTML の属性の値にデータをバインドしているだけです.
v-if / v-else: 条件付きレンダリング
<div class="card" v-for="book in books">
<h2>{{ book.title }}</h2>
<p>{{ book.description }}</p>
<p v-if="book.tags.length === 0">タグなし</p>
<div v-else>
<span class="tag" v-for="tag in book.tags">
{{ tag }}
</span>
</div>
</div>
v-if も HTML の属性です.hidden 属性を書くような感覚で使えます.
完全なコード
ここまでの内容をまとめた完全なコードです.
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My App</title>
<style>
body {
font-family: sans-serif;
max-width: 600px;
margin: 40px auto;
padding: 0 20px;
}
.card {
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 20px;
margin-bottom: 16px;
}
.card h2 { margin-top: 0; }
.tag {
display: inline-block;
background: #edf2f7;
border-radius: 4px;
padding: 2px 8px;
font-size: 0.85em;
margin-right: 4px;
}
</style>
</head>
<body>
<div id="app">
<h1>My Bookshelf</h1>
<p>最近読んだ本の記録です.</p>
<div class="card" v-for="book in books">
<h2>{{ book.title }}</h2>
<p>{{ book.description }}</p>
<span class="tag" v-for="tag in book.tags">
{{ tag }}
</span>
</div>
</div>
<script type="importmap">
{
"imports": {
"vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.js"
}
}
</script>
<script type="module">
import { createApp, ref } from 'vue'
createApp({
setup() {
const books = ref([
{
title: 'リーダブルコード',
description: '読みやすいコードを書くための実践的な技法.',
tags: ['programming', 'practices']
},
{
title: 'プログラミング言語の基礎概念',
description: '言語の設計を支える根本的な概念を学ぶ.',
tags: ['cs', 'language']
},
{
title: 'Web ブラウザセキュリティ',
description: 'ブラウザに関するセキュリティを体系的に解説.',
tags: ['security', 'browser']
}
])
return { books }
}
}).mount('#app')
</script>
</body>
</html>
ブラウザで開くと,前章と まったく同じ見た目 です.
しかし裏側では,データとビューが分離されています.
本を追加したければ,books 配列にオブジェクトを足すだけです.
テンプレートは「別言語」ではない
React の JSX は JavaScript の拡張です.書くためには Babel などのトランスパイラが必要です.
Angular のテンプレートは独自の構文が多く,HTML からはかなり離れています.
Vue のテンプレートは HTML そのもの に,いくつかの属性 (v-for, v-if, v-bind) と {{ }} を足しただけです.
- HTML を書ける人なら,すぐに読める
- ブラウザの DevTools でそのまま見える
- HTML のバリデーターも(ほぼ)通る
テンプレートが HTML であること — これは Vue の最大の強みの一つです.
まとめ
- Vue のテンプレートは valid な HTML にディレクティブを足したもの
{{ }}でデータを表示するv-forでリストを生成する(HTML 属性として書く)v-bind(:) で属性にデータをバインドするv-if/v-elseで条件付き表示をする- テンプレートの構造は 静的 HTML とほぼ同じ まま
- ファイルは依然として
index.html一枚