LoginSignup
230
158

More than 3 years have passed since last update.

Vue.jsの <template>タグには複数の役割がある

Posted at

先に結論書いてしまいますと、全部公式ドキュメントに書いてあります。

でも、書いてある箇所がバラバラなので
先に公式ドキュメントをちゃんと目を通していれば混乱しないのでしょうが、
ちゃんと読まずにいきなり現場のソースコード読んで、まぁどうにかなんだろうと思ったら
ん?この <template><template> はなんか違うの?? と混乱してしまった人(私です)向けにまとめました。

<template> タグには以下の役割があります。

  • 条件付きレンダリングで複数要素を対象とする場合(v-if)
  • リストレンダリングで複数要素を対象とする場合(v-for)
  • 名前付きスロット(v-slot)
  • 単一ファイルコンポーネント

条件付きレンダリングで複数要素を対象とする場合(v-if)

公式ドキュメントはこちら
https://jp.vuejs.org/v2/guide/conditional.html#%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%81%A7%E3%81%AE-v-if-%E3%81%AB%E3%82%88%E3%82%8B%E6%9D%A1%E4%BB%B6%E3%82%B0%E3%83%AB%E3%83%BC%E3%83%97

公式サイトにある例を引用:

<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>

v-if 属性を持った <template> タグは、 条件付きレンダリングです。

上の例でいうと、oktrue と評価される場合、以下のようにレンダリングされます。

  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>

<template> タグ自体はレンダリングされません。

リストレンダリングで複数要素を対象とする場合(v-for)

公式ドキュメントはこちら
https://jp.vuejs.org/v2/guide/list.html#lt-template-gt-%E3%81%A7%E3%81%AE-v-for

公式サイトにある例を引用:


<ul>
  <template v-for="item in items">
    <li>{{ item.msg }}</li>
    <li class="divider" role="presentation"></li>
  </template>
</ul>

v-for 属性を持った<template> タグは、 リストレンダリングです。

上の例でいうと、例えば items[{msg: "foo"},{msg: "bar"},{msg: "baz"}] なら
以下のようにレンダリングされます。


<ul>
    <li>foo</li>
    <li class="divider" role="presentation"></li>
    <li>bar</li>
    <li class="divider" role="presentation"></li>
    <li>baz</li>
    <li class="divider" role="presentation"></li>
</ul>

<template> タグ自体はレンダリングされません。

名前付きスロット(v-slot)

公式ドキュメントはこちら
https://jp.vuejs.org/v2/guide/components-slots.html#%E5%90%8D%E5%89%8D%E4%BB%98%E3%81%8D%E3%82%B9%E3%83%AD%E3%83%83%E3%83%88

こちらはまず「コンポーネント」の理解から始めないといけないのですが
その説明をしだすと長くなるので、公式ドキュメントをみていただくとして、雑に説明すると

「コンポーネント」は、Vueの要素を部品化したもので
「スロット」は、コンポーネントを利用する際に、コンポーネントを呼び出す側からデータ等を渡すことができるのですが、それをはめ込む要素
のことです。

公式サイトの例を一部修正して引用 1

base-layout というコンポーネントが、以下のような構成だったとして。

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot name="main"></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

base-layoutを呼び出す側で、スロットに入れたい内容を、 v-slot 属性を指定した <template> タグで指定します。

<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>

  <template v-slot:main>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </template>

  <template v-slot:footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>

実際のレンダリングは以下の通り:

<div class="container">
  <header>
    <h1>Here might be a page title</h1>
  </header>
  <main>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </main>
  <footer>
    <p>Here's some contact info</p>
  </footer>
</div>

単一ファイルコンポーネント

公式ドキュメントはこちら
https://jp.vuejs.org/v2/guide/single-file-components.html

中規模以上のアプリケーションを実装していく場合
コンポーネントをそれぞれのファイル(.vueファイル)に分割し
webpack等でビルドする…という流れになります。

この時、コンポーネント化された.vueファイルで
HTML部、JavaScript部、CSS部を分離したとき、
HTML部のルート要素として <template> タグ を指定します。

公式ドキュメントより引用

<template>
  <p>{{ greeting }} World!</p>
</template>

<script>
module.exports = { 
  data: function () { 
    return { 
      greeting: 'Hello' 
    } 
  } 
} 
</script> 

<style scoped>
p {
  font-size: 2em;
  text-align: center;
}
</style>

  1. デフォルトスロットの説明がまた面倒なので、デフォルトスロットを使わない説明に変えています。 

230
158
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
230
158