SHOEISHA iD

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

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

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

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

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

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

Content Insertion

 Content Insertionは、コンポーネント自身以外のエレメントをコンポーネント自身の特定の位置に挿入することができる仕組みです。うまく活用すればとても再利用性の高いコンポーネントを提供することができます。例えば、外側の枠としての役割を担うTabやDialogなどを再利用可能なコンポーネントとして提供し、その中に表示するコンテンツを別のエレメントとして受け取って表示することなどができます。Web Componentsが策定している<content>と同じ概念で、AngularJSにおけるtransclusionにも類似した概念です。

 まず、template内に<content>タグをもつコンポーネントを定義します。次に、コンテンツとなるエレメントをコンポーネントの内側のノードとして記述すると、実行時にコンテンツとなるエレメントがtemplate内の<content>タグの部分に挿入されます。

リスト12. Content Insertionの例
<div id="app">
    <my-component>
      <p>This is some original content</p>
      <p>This is some more original content</p>
    </my-component>
</div>
<script>
    var parent = new Vue({
        el: '#app',
        components: {
            'my-component': {
                template: '<h1>This is my component!</h1><content>このメッセージは何もcontentが挿入されなかった時のみ表示される</content>',
            }
        }
    });
</script>

 上記のコードを実行した結果は以下のようになります。

図4. Content Insertionの実行例
図4. Content Insertionの実行例

 なお、<content>タグを複数用いて受け渡しされる複数のエレメントを別々に割り振りたい場合は、<content>のselect属性にCSSセレクタを指定することも可能です。詳しくは公式ドキュメントをご参照ください。

コンポーネント間のイベント

 Vue.jsでは、コンポーネントを複数組み合わせてアプリケーションを構築するために、コンポーネント間でイベントをやり取りする仕組みが用意されています。親子間でVMインスタンスに直接アクセスすることもできますが、イベント通信の仕組みを利用することで疎結合なコンポーネント間の連携を実現できます。一度親子間の関係が構築されるとVue.jsでは以下の表に示すイベントのやりとりが可能になります。

表4. コンポーネント間のイベント
項目 説明
$dispatch(event, [args...]) 指定したイベントを自身の親方向へ発信する。$rootまで順番伝播され、callbackがfalseを返した場合はその伝播が中断される。
$broadcast(event, [args...]) 親から子方向へイベントを発信する。末端の子まで伝播し、callbackでfalseを返した場合は伝播がそのインスタンス自身以降は中断される。
$emit(event, [args...]) 自身のインスタンス内のみでイベントを発信する。
$on(event, callback) 特定のイベントをlistenし、そのイベントに対するcallbackを登録する。
$once(event, callback) 特定のイベントに対して、一度だけ呼ばれるcallbackを登録する。
$off([event, callback]) 引数がない場合はlistenしているすべてのイベントを削除する。eventとcallbackが与えられた場合は、指定したeventに対するcallbackを削除する。

 以下の例では、初期化時に子コンポーネントがイベントをdispatchして、親がそのイベントに対してcallbackを呼び出しています。

リスト13. コンポーネント間のイベントの例
<div id="parent">
    <div v-component="child"></div>
</div>
<script>
var Child = Vue.extend({
    template: '<div>This is a child.</div>',
    created: function () {
        this.$dispatch('child-created', this);
    }
});
var parent = new Vue({
    el: '#parent',
    components: {
        child: Child
    },
    created: function () {
        this.$on('child-created', function (child) {
            console.log('new child created: ');
            console.log(child);
        });
    }
});
</script>

コンポーネントにおけるディレクティブのスコープ

 コンポーネント使用時のエレメントに対するディレクティブ(v-showやv-onなど)のスコープは親のものになります。

 以下の例のコンポーネントに指定しているエレメント上のv-onは親スコープのonClickParentが参照されます。同様に、Content Insertionによってコンポーネントへ挿入されるエレメントで指定するv-showディレクティブも親スコープです。一方、コンポーネント自身のテンプレート上のv-onディレクティブでは、スコープがコンポーネント自身となります。

リスト14. ディレクティブのスコープ
<div id="app">
    <input v-model="parentMsg">
    <!-- componentを指定するエレメントとContent Insertion上でのディレクティブは親スコープ -->
    <div v-component="child" v-with="childMsg: parentMsg" v-on="click: onClickParent">
        <span v-show="active">Content Insertionされる要素も親のスコープが適用される</span>
    </div>
</div>
<script>
    var parent = new Vue({
        el: '#app',
        data: {
            active: true,
            parentMsg: 'Inherited message'
        },
        methods: {
            onClickParent: function(){
                alert("parent clicked");
            }
        },
        components: {
            child: {
                // コンポーネント内テンプレートで指定するディレクティブは子自身のスコープ
                template: '<span v-on="click: onClickChild">{{childMsg}} <content></content></span>',
                methods: {
                    onClickChild: function(){
                        alert("child clicked");
                    }
                }
            }
        }
    });
</script>

ダイナミックコンポーネント

 v-componentの値にMustache記法による変数を指定することで動的にコンポーネントが切り替わる仕組みがダイナミックコンポーネントです。

リスト15. ダイナミックコンポーネントの例
<div id="app">
    <ul>
        <li><a v-on="click: switchView('home')">Home</a></li>
        <li><a v-on="click: switchView('posts')">Post</a></li>
        <li><a v-on="click: switchView('archive')">Archive</a></li>
    </ul>
    <div v-component="{{currentView}}" keep-alive>
    <!-- 展開されるコンポーネントがvm.currentviewの値に応じて変わる -->
    </div>
</div>
<script>
    var parent = new Vue({
        el: '#app',
        data: {
            currentView: 'home'
        },
        methods: {
            switchView: function(componentId){
                this.currentView = componentId;
            }
        },
        components: {
            home: {
                template: '<p>This is Home.</p>'
            },
            posts: {
                template: '<p>This is Posts.</p>'
            },
            archive: {
                template: '<p>This is Archive.</p>'
            }
        }
    });
</script>

 上記の例ではダイナミックコンポーネントのkeep-aliveというディレクティブのパラメーターを与えています。keep-aliveがセットされていると、コンポーネントが切り替わって再度表示される際に、以前のコンポーネントの状態が保持され、DOMの再レンダリングを避けることができます。

最後に

 本稿では、Vue.jsの再利用性の高いモジュールを提供するための仕組みであるカスタムフィルター、カスタムディレクティブ、コンポーネントについて公式ドキュメントを元に解説しました。

 次回以降も引き続きVue.jsに関する記事の続編を執筆する予定です。より本格的な自作コンポーンネントの例や、トランジション、モジュール管理、ルーター、Ajax通信など、本格的にアプリケーション開発をしていく上で必要となる仕組みについて紹介したいと思います。

 LINE株式会社ではJavaScriptエンジニアを募集しています。私たちと一緒にプラットフォーム・グローバル展開を発展させていきたい方はぜひご応募ください。

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

  • 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」など、さまざまなカンファレンスを企画・運営しています。

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

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

メールバックナンバー

アクセスランキング

アクセスランキング