SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

LINEフロントエンドレンジャーのWeb開発術

お手軽データバインディングライブラリ「Vue.js」を使いこなそう(コンポーネント編)

LINEフロントエンドレンジャーのWeb開発術 第4回

  • X ポスト
  • このエントリーをはてなブックマークに追加

コンポーネント

 Vue.jsはWeb Componentsのコンセプトを取り入れたコンポーネントの仕組みを持っています。コンポーネントはデータの定義とDOMの構築などを含めた部品を作成することができる仕組みです。親子コンポーネント間でイベントを通じたデータのやりとりも可能です。

 Polymerなどに代表されるようなPolyfillへの外部依存はなく、Vue.extend()を使ってコンポーネントを作成することができます。Vue.extend()を使用するときに渡すオプションに関しては、前回の記事で解説したVMインスタンスを生成する際のオプションとほとんど同じです。

 ただし、elとdataオプションに関して、再利用され複製される用途が主であるコンポーネントでは、インスタンスごとに初期化した値を渡すためにfunctionとして定義する点が異なります。

 コンポーネントのライフサイクルに関しては、前回の記事で紹介したVMインスタンスのライフサイクルと同じです。

 Vue.extend()でコンポーネントの必要なオプションを記述して、実際にカスタムエレメントとして登録するにはVue.component()を呼びます。以下、dataに与えた値を表示するだけの簡単なコンポーネントの例です。

リスト6. コンポーネントの例
<div id="app">
    <!-- v-componentを使用する方法 -->
    <div v-component="my-component"></div>
    <!-- カスタムエレメントとして使用する方法 -->
    <my-component></my-component>
</div>
<script>
var MyComponent = Vue.extend({
    template: 'A custom component {{title}}',
    data: function(){
        return {title: 'カスタムエレメント'}
    }
});
// コンポーネントを登録
Vue.component('my-component', MyComponent);
var vm = new Vue({
    el: '#app'
});
</script>

 上記のコードを実行すると”A custom component カスタムエレメント”という文字列がv-componentによる記述と、カスタムエレメント形式の記述で2つ表示されます。

 Vue.extend()を省略した簡易的な記述も可能です。Vue.component()の第2引数にVue.extend()へのオプションを直接セットします。

リスト7. Vue.extendを省略する例
// Vue.extendを省略して以下のように記述することもできる
Vue.component('my-component', {
    template: 'A custom component {{title}}!',
    data: function(){
        return {title: 'カスタムエレメント'}
    }
});

 親VMインスタンスの中で自身の配下にコンポーネントを直接登録することもできます。その場合は、Vue.compoent()を使ったグローバルな登録は必要なく、親VMインスタンス生成時のcomponentsオプションとして指定します。

コンポーネントをカスタムエレメントとして記述する場合の注意点

 W3Cが提唱するカスタムエレメントの仕様として、タグには必ずハイフン(-)を1つ以上含める必要があります。Vue.jsのコンポーネントもWeb Componentsの仕様に準拠するためにv-componentを使わずにカスタムのタグ名で記述する場合はハイフンを含める必要があります。

 また、カスタムエレメントはブラウザにとって未知のタグであるため、div要素にv-componentを指定する時とは異なりデフォルトではブロック要素として解釈されないので注意が必要です。

コンポーネントへのデータの受け渡し

 Vue.component()で登録されたコンポーネントはカスタムフィルターやカスタムディレクティブと同様にグローバルに登録され、デフォルトでは親スコープのデータとは独立しています。明示的にコンポーネントへデータを渡したい場合はv-withを使うことができます。また、配列に対してはv-repeatを使うことができます。

v-withを使用したデータの受け渡し

 v-withを使用して親から子コンポーネントへ直接オブジェクトを指定する例を紹介します。親Vueインスタンスの$dataのオブジェクトuserを引数なしに指定すると、子コンポーネントの$dataとしてセットされます。

リスト8. v-withで引数なしオブジェクトを指定
<div id="app">
    <p v-component="user-profile" v-with="user"></p>
</div>
<script>
    // コンポーネントを登録する$dataに対応するオブジェクトはv-withで親から与えられる
    Vue.component('user-profile', {
        template: '{{name}}<br>{{email}}'
    });
    var parent = new Vue({
        el: '#app',
        data: {
            user: {
                name: 'Foo Bar',
                email: 'foo@bar.com'
            }
        }
    });
</script>

 v-withで子コンポーネントにデータを渡す際に、引数にプロパティを指定することができます。v-with="childProp: parentProp"の形式で渡すと、parent[parentProp]child[childProp]が双方向でバインディングされます(v0.11.5時点)。

 双方向のバインディングの例を示すために、以下ではコンポーネントが受け取った値をクリック時に変更しています。クリック時の値の変更によりparent側のプロパティ値も動的に変更されます。

リスト9. v-withでプロパティを指定した双方向バインディングの例
<div id="app">
    <input v-model="parentMsg">
    <p v-component="child" v-with="childMsg : parentMsg"></p>
</div>
<script>
    var parent = new Vue({
        el: '#app',
        data: {
            parentMsg: 'Inherited message'
        },
        components: {
            child: {
                template: '<span v-on="click: update">{{childMsg}}</span>',
                methods: {
                    update: function(){
                        // childMsgを更新すると動的に親のparentMsgも変更される
                        this.childMsg = "Updated message by child";
                    }
                }
            }
        }
    });
</script>

v-repeatを使用したデータの受け渡し

 v-repeatを用いてコンポーネントにオブジェクトの配列を渡すことができます。配列のそれぞれのオブジェクトに対してViewModelが生成され、コンポーネントのデータとしてセットされます。

リスト10. v-repeatを使用したデータの受け渡し
<div id="app">
    <ul>
        <li v-repeat="users" v-component="user-profile"></li>
    </ul>
</div>
<script>
    var parent = new Vue({
        el: '#app',
        data: {
            users: [
                {
                    name: 'Chuck Norris',
                    email: 'chuck@norris.com'
                },
                {
                    name: 'Bruce Lee',
                    email: 'bruce@lee.com'
                }
            ]
        },
        components: {
            'user-profile': {
                template: '{{name}}<br>{{email}}',
            }
        }
    });
</script>
図3. v-repeatを使用したデータの受け渡し実行例
図3. v-repeatを使用したデータの受け渡し実行例

v-refによる子コンポーネントの参照

 親VMインスタンスから子コンポーネントへアクセスが必要な場合は以下のようにv-refをセットすることで参照することができます。

リスト11. v-refによる子コンポーネントへの参照
<div id="parent">
    <div v-component="user-profile" v-ref="profile"></div>
</div>
<script>
Vue.component('user-profile', {
    template: 'This is a user profile'
});
var parent = new Vue({ el: '#parent' });
// 子コンポーネントへv-refで指定した値でアクセスできる
var child = parent.$.profile;
</script>

次のページ
最後に

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
LINEフロントエンドレンジャーのWeb開発術連載記事一覧

もっと読む

この記事の著者

手島 拓也(LINE株式会社)(テジマ タクヤ)

日本IBM研究所にて検索・テキスト解析ソフトウェア製品の開発に従事した後、現在はLINEにてWebフロントエンド開発を担当。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/8567 2015/04/10 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング