【Vue.js】コンポーネントのtemplateの書き方まとめ

大きく以下の4つの書き方があります（もっとあるかも）

1. [文字列](#1%E6%96%87%E5%AD%97%E5%88%97)
2. [X-template](#2x-template)
3. [.vue コンポーネント](#3vue-%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88)
4. [描画関数](#4%E6%8F%8F%E7%94%BB%E9%96%A2%E6%95%B0)

1.文字列
------------------------------
一番スタンダードな方法と言えるでしょう。
文字通り文字列で記述します。

```js
Vue.component('my-component', {
  template: '<div>A custom component!</div>'
})
```

また、tipsですがES6以上なら `` で囲むことによって複数行にまたがって記述することができるので可読性が上がります。  
ダブルクオート使うメリットもないはずなので、とりあえずこっち使っとくのがよいのではと思います。

```js
Vue.component('my-component', {
  template: `<div>
              A custom component!
             </div>`
})
```

そして[こちらの解説](https://jp.vuejs.org/v2/guide/components.html#DOM-テンプレート解析の注意事項)に詳しいんですが、
いくつかのタグには制約(例えば`<ul>`タグの直下には`li`しか表示できない、みたいな)が存在しており、
それをエラーとして検出できるのはこの記述方法のみとのことです。
おかしなDOMを作ることを検知できるのは一つのメリットかもしれません。

2.X-template
------------------------------
参照:[https://jp.vuejs.org/v2/guide/components.html#x-template](https://jp.vuejs.org/v2/guide/components.html#x-template)

こんな感じでHTML内に定義して

```html
<script type="text/x-template" id="my-component">
  <div>A custom component!</div>
</script>
```

JSからはID指定で読み込むことができます。


```js
Vue.component('my-component', {
  template: '#my-component'
})
```

JS内からはID指定するのみなので大分さっぱりします。
ただドキュメントでも言及されている通り、テンプレートの記述がコンポーネントから分離されて
管理が煩雑になりそうなので、プロダクションで使うには良い選択肢ではなさそうです。

3.`.vue` コンポーネント
------------------------------
参考:[vue.jsのcomponentをwebpackで.vueにして単一ファイルコンポーネントにする](https://qiita.com/tkhr/items/ac22019c891fe8fa5f91)

`.vue`の拡張子のファイルを作成し、下記のようにtemplateを記述します。

```html:my-component.vue
<template>
  <div>A custom component!</div>
</template>
```

JSからは以下のように読み込めます。

```js
import MyComponent from './my-component.vue';

new Vue({
  el: '#example',
  components: { MyComponent },
  template: '<my-component>'
})
```

メリットについては上記の参考記事にすごくよくまとまっているので、是非ご参照ください。
個人的にはこの書き方が一番幸せになれそうな予感がしています。

4.描画関数
------------------------------
参照: [https://jp.vuejs.org/v2/guide/render-function.html](https://jp.vuejs.org/v2/guide/render-function.html)
厳密には`templateの書き方`ではなく`templateを代替するもの`という捉え方の方が適切っぽいです。

ドキュメントの例をそのまま拝借します。
下記のようなHTMLの構成のコンポーネントを作成、また、`h*`タグ の数字の部分をコンポーネントのpropsのlevelによって決めたいとします。

```html
<h1> <!-- ここをlevelによって変動させたい -->
  <a name="hello-world" href="#hello-world">
    Hello world!
  </a>
</h1>
```

愚直にtemplateでやろうとすると下記のようになってしまいます

```html
<script type="text/x-template" id="anchored-heading-template">
  <h1 v-if="level === 1">
    <slot></slot>
  </h1>
  <h2 v-else-if="level === 2">
    <slot></slot>
  </h2>
  <h3 v-else-if="level === 3">
    <slot></slot>
  </h3>
  <h4 v-else-if="level === 4">
    <slot></slot>
  </h4>
  <h5 v-else-if="level === 5">
    <slot></slot>
  </h5>
  <h6 v-else-if="level === 6">
    <slot></slot>
  </h6>
</script>
```

いかにも冗長ですね。
これをRender関数を使えば以下のように書けます。

```js
Vue.component('anchored-heading', {
  render: function (createElement) {
    return createElement(
      'h' + this.level,   // タグ名
      this.$slots.default // 子の配列
    )
  },
  props: {
    level: {
      type: Number,
      required: true
    }
  }
})
```

また、[Babelプラグイン](https://github.com/vuejs/babel-plugin-transform-vue-jsx)を使えば以下のようにJSXで記述することもできるみたいです。

```js
import AnchoredHeading from './AnchoredHeading.vue'

new Vue({
  el: '#demo',
  render (h) {
    return (
      <AnchoredHeading level={1}>
        <span>Hello</span> world!
      </AnchoredHeading>
    )
  }
})
```

よりプログラマブルにDOMの中身を出し分けたいという場合に描画関数が適している状況もありそうです。
ちょっと私の経験では動的にタグ名とかを書き換えたい、の様などうしても動的に出し分けないと辛いみたいな要求に出会ったことがないので、文字列でサクッと書くことに比べた有用性がイメージしづらいですが、知識として知っておいて損はない書き方かなと感じました。