初心者向:Vue.js コンポーネント作成がうまくいかないときにチェックする5つのこと

こちらVue.js #4 Advent Calendar 20174日目の記事です~。

どもども。ソニックムーブっていう会社で、マークアップしたりJavascriptをちょいちょい触ったりしているココエっていいます。
最近Vue.js絡みの仕事ばっかりやっていて、初心者の方にVue.jsの使い方を教える機会がでてきたので、こんな記事を書いてみようと思いました。

やっぱり最初の難関がコンポーネント作成ですよね。
チュートリアル見ながら、コンポーネント作ってみたけど、なんかうまくいかなーーーい!という方は、後述する、コンポーネント作成がうまくいかないときにチェックする5つのことをチェックしてみてください。
お役に立てればこれ幸い。

コンポーネントのテンプレートのルート要素は1つのみ

おおよそ初心者の方がハマるのがここ。
2系からなのですが、コンポーネントのテンプレートのルート要素は1つしか持つことができません

公式には、
https://jp.vuejs.org/v2/guide/migration.html#テンプレート
こちらに、さらっと書いてあったりします。

どういうことか例をあげます。まず、以下がうまくいかない例。

<div id="app">
  <my-component></my-component>
</div>

<script type="text/x-template" id="tpl_my_component">
  <div>ほげ</div>
  <div>ふが</div>
</script>

<script>
  (function() {

    var myComponent = {
      template: '#tpl_my_component',
    };

    var vm = new Vue({
      el: '#app',

      components: {
        'my-component': myComponent
      },
    });

  })();
</script>

https://jsfiddle.net/kokoe/xenqynw2/

こちらは、実行すると「ほげ」しか表示されません。(「ふが」が表示されない。)
コンポーネントのテンプレート(#tpl_my_component)の直下(ルート)には、要素(div)が2つ存在しているため、正しく表示されないようですね。

「あれっ、作ったコンポーネントが全部表示されない!」
ってあたふたしている場合、こんなオチだったりしますします。

コンポーネントのテンプレートのルート要素でv-forしない

前述と同じことですが、テンプレート直下(ルート)でv-forを使うと、これまた、正しく表示されません。v-forで引き回す配列値が1つのみだったとしても表示されません。

<div id="app">
  <todo v-bind:items="todoList"></todo>
</div>

<script type="text/x-template" id="tpl_todo">
  <div v-for="item in items" v-bind:key="item">
    {{ item.title }}
  </div>
</script>

<script>
  (function() {

    var myComponent = {
      template: '#tpl_todo',
      props: ['items']
    };

    var vm = new Vue({
      el: '#app',

      components: {
        'todo': myComponent
      },

      data: {
        todoList: [{
          title: '歯磨き',
          isDone: false
        }, {
          title: '手洗い',
          isDone: false
        }, {
          title: 'にらめっこ',
          isDone: false
        }, ]
      }
    });

  })();
</script>

https://jsfiddle.net/kokoe/Lj45jrdo/

テンプレートは、インラインテンプレートで指定していようが、script[type=text/x-template]で指定していようが同じで、ルートは要素は1つのみなのです。

templateって正しく書いてますか

自身の体験談でお恥ずかしい限りですが

var myComponent = {
  template: '#tpl_my_component'
};

この template っていう単語。
templete とか tamplate とかになっていませんか?!w
いわゆるスペルミスです。急いでいる時とか気づかないもんなのです。。。
スペルミスしている時、Developer Toolsで該当の要素を覗いてみると

<!--function (t,n,r,i){return mt(e,t,n,r,i,!0)}-->

こんなんでていたりするので、その場合はスペルミスを疑ってみたらよいと思います。

こちらにスペルミスの例をあげてます。
https://jsfiddle.net/kokoe/vh0m14La/

v-bindでコンポーネントに渡す値が抜けてませんか?

以下もうまくいかない例です。
my-componentのhogeにv-bindで値を渡し忘れている例です。

これを実行しても、コンポーネントの部分だけでなく、new Vueでマウントしているルート自体が表示されません。


<div id="app">
  <my-component v-bind:hoge=""></my-component>
</div>

<script type="text/x-template" id="tpl_my_component">
  <div>ほげ</div>
</script>

<script>
  (function() {

    var myComponent = {
      template: '#tpl_my_component',
      props: ['hoge']
    };

    var vm = new Vue({
      el: '#app',

      components: {
        'my-component': myComponent
      },
    });

  })();
</script>

https://jsfiddle.net/kokoe/j5xqvu7y/

Developer Toolsで要素を覗いてみると、new Vueでマウントしている要素が

<!---->

こんな感じでコメントアウトが入っています。
v-bindで値を渡し忘れていないかチェックしてみてくださいね。
(そんなことあるのかって突っ込まれそうですが、後で値いれようと思ってて忘れちゃったりするのです。。)

new Vueでマウントしている要素(ルート)の中にテンプレートファイルをいれない

コンポーネントのテンプレートを、script[type=text/x-template]で指定している場合、割とやりがちなミスだったりします。

以下、うまくいかない例です。
これを実行すると、ReferenceError: text is not defined と怒られます。

<div id="app">
  <my-component></my-component>

  <script type="text/x-template" id="tpl_my_component">
    <div>{{ text }}</div>
  </script>
</div>

<script>
  (function() {

    var myComponent = {
      template: '#tpl_my_component',
      props: ['text']
    };

    var vm = new Vue({
      el: '#app',

      components: {
        'my-component': myComponent
      },
    });

  })();
</script>

https://jsfiddle.net/kokoe/rsrcy2w5/

new Vue でマウントしている要素の中にMustache(二重中括弧)が入ると、script要素の中であろうがなかろうが、対応するオブジェクトプロパティの値に置き換えられます。(上記の例だと text プロパティ値を探しに行く。で、無いから怒られる)

ということで、コンポーネントのテンプレートをscript[type=text/x-template]で作成する場合は、new Vue でマウントしている要素の中に入らないように気を付けましょう。

1473689334
怖くないよ~怒ってないよ~