初心者向: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
でマウントしている要素の中に入らないように気を付けましょう。