Help us understand the problem. What is going on with this article?

vue.jsのカスタムコンポーネントをちゃんと使う

More than 3 years have passed since last update.

カスタムコンポーネントを使おうとして、公式ドキュメントをはじめとしていろんな情報を漁っても、
親から子にdataを渡して子ではテンプレートに表示してるだけ、みたいなシンプルすぎてよくわからないサンプルばかり見つかるので、自分で試しながら理解した点をまとめます。

親からデータを渡された後はコンポーネント側で自立して状態保持・変更を行うようなサンプルを書いてみました。

index.html
<script language="javascript" src="http://cdnjs.cloudflare.com/ajax/libs/vue/1.0.24/vue.js"></script>

<div id="app">
    <pattern-component v-for="pattern in partterns" :pattern="pattern" track-by="$index"/>
</div>

<script>
    var patternComponent = Vue.extend({
        data: function(){
            return { 
                list: ["", "", "×", ""]
            }
        },
        props: [ 'pattern' ],
        methods: {
            change: function(){
                this.pattern++;
                if(this.pattern >= this.list.length){
                    this.pattern = 0;
                }
            },
        },
        computed: {
            mark : function(){
                return this.list[this.pattern];
            },
        },
        template: '<li @click="change">{{mark}}</li>'
    });

    var app = new Vue({
        el: '#app',
        data: {
            partterns: [ 0, 0, 0, 0 ]
        },
        components: {
            'pattern-component': patternComponent
        }
    })
</script>

カスタムコンポーネントの基本的な使い方

公式ドキュメントはなんかつらつら書いてありますが、Vue.extend({})で定義して、Vue.component()で登録して使います。Vue.component()で定義しても動きますが、別ファイルに切り出せるようになるというのはカスタムコンポーネントの利点の一つなので、わざわざ固めてしまうモチベーションはよくわかりませんでした。
参考:http://jp.vuejs.org/guide/components.html#コンポーネントの使用

v-forから渡ってくるデータについて

<my-component v-for="childProp in parentList" :childProp="childProp"/>

みたいな書き方をすると、patentListの1つの要素がmy-componentchildPropに渡されます。
サンプルでは各子コンポーネントに渡すプロパティが同一値であるため、track-byパラメータを指定するようにと[Vue warn]がでました。同一のプロパティで初期化する場合は注意しましょう。

vue.js:1018 [Vue warn]: Duplicate value found in v-for="pattern in partterns": 0. Use track-by="$index" if you are expecting duplicate values.

参考: https://jp.vuejs.org/guide/components.html#コンポーネントと-v-for

templateについて

もっと大きく複雑になる場合は、<template>を使って別ファイルに切り出して、JSコード側からはidで指定するようにすべきだと思います。
また、いろんなところで子コンポーネントのテンプレート内に親のデータをアサインしているような使い方がされているのを見かけましたが、カスタムコンポーネントとして使うならちゃんと分離しておく方が見通しも再利用性もよくなりそうな気がします。

methods, computedについて

普通に new Vue({...})する時と全く同じように使えました。
カスタムコンポーネント内に定義することによって、親のVMでは実際に表示されるマークについて全く意識する必要がなくなり良い感じです。

バインディングについて

何も考えずに使うとデフォルトがone-wayバインディングで、子から親への伝搬が行われないので注意が必要です。子から親へ伝搬させたい場合はプロパティを渡す時に .syncを指定してやる必要があります。
参考:http://jp.vuejs.org/guide/components.html#Prop-バインディングタイプ

感想

  • カスタムコンポーネントをちゃんと活用するとファイルが分けられる/責務が分割できる/見通しがよくなるなど一般的なクラス分けの恩恵を受けられそうです。ガンガン使いましょう。
  • 今回書いたサンプルのlistの部分をmixinで拡張すれば、コンポーネントの使い勝手が上がりそうだなと思ったんですが、今回はそこまで手が回らなかったのでmixin拡張しやすいインタフェースについてもそのうち考えます
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした