38
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Vueインスタンスとコンポーネントの関係

Posted at

はじめに

オブジェクトリテラルの観点でVueインスタンス、コンポーネントを整理してみる。
これによって、

  • ルートVueインスタンス
  • グローバルコンポーネント
  • ローカルコンポーネント

3つのVueインスタンスがそれぞれ何故そういう書き方になるのかがクリアになる。また、単一ファイルコンポーネント等のより発展的な内容についても理解の助けになる。本記事では、「ルートVueインスタンスとは?」「コンポーネントとは?」といった、そもそものところについては触れないけれども、それらについてなんかしっくりこない感じがあるひとに対しては何かしら役に立つかもしれない。

  • 本記事では、Vueインスタンス、コンポーネントの生成時に記述されるオブジェクトリテラルを便宜上Vueオブジェクトと呼ぶことにしています。
  • 記事内のサンプルコードはCDNでVueを読み込めば動く内容です。
  • サンプルコードの結果はルートVueインスタンス、グローバルコンポーネント、ローカルコンポーネントで、ほぼ同じです。

Vueオブジェクトによる整理

まずは、ルートVueインスタンス、グローバルコンポーネント、ローカルコンポーネントについて、それぞれ導入的な書き方からVueオブジェクトの観点で整理した書き方に変更する。

ルートVueインスタンス

よくある導入的な書き方。

<div id="container">
    <p>{{ comments }}.</p>
</div>
// ルートVueインスタンス
new Vue({
    el: '#container',
    data: {
        comments: "hello in root"
    }
});
# ブラウザ出力
hello in root.

ルートVueインスタンスを生成するnew Vue()の引数はオブジェクトリテラル。これをVueオブジェクトとして外に出す。

// ルートVueオブジェクト
// new Vue()の引数を外に出した
let rootVueObj = {
    el: '#container',
    data: {
        comments: "hello in root"
    }
};
// ルートVueインスタンス
// rootVueObjを登録
new Vue(rootVueObj);

グローバルコンポーネント

よくある導入的な書き方。

<div id="container">
    <g-component></g-component>
</div>
// グローバルコンポーネント
Vue.component('g-component', {
    data: function () {
        return {
            comments: "hello in global component"
        }
    }
    , template: '<p>{{ comments }}.</p>'
});

// ルートVueインスタンス
new Vue({ el: '#container' });
# ブラウザ出力
hello in global component.

ルートVueオブジェクトについては前章同様。
グローバルコンポーネントを生成するVue.component()の第二引数はオブジェクトリテラル。これもコンポーネントVueオブジェクトとして外に出す。

// コンポーネントVueオブジェクト
// Vue.component()の第二引数の内容を外に出した
let componentVueObj = {
    data: function () {
        return model
    }
    , template: '<p>{{ comments }}.</p>'
};

// ルートVueオブジェクト
// new Vue()の引数を外に出した
let rootVueObj = {
    el: '#container'
};

// グローバルコンポーネント
// componentVueObjを登録
Vue.component('g-component', componentVueObj);

// ルートVueインスタンス
// rootVueObjを登録
new Vue({rootVueObj);

ローカルコンポーネント

よくある導入的な書き方。

<div id="container">
    <l-component></l-component>
</div>
// コンポーネントVueオブジェクト
let componentVueObj = {
    data: function () {
        return {
            comments: "hello in local component"
        }
    }
    , template: '<p>{{ comments }}.</p>'
};

// ルートVueインスタンス
new Vue( {
    el: '#container', 
    components: {
        'l-component': componentVueObj
    }
});    
# ブラウザ出力
hello in local component.

ルートVueオブジェクトについてこれまで同様外に出す。

let componentVueObj = {
    data: function () {
        return {
            comments: "hello in local component"
        }
    }
    , template: '<p>{{ comments }}.</p>'
};

// ルートVueオブジェクト
// new Vue()の引数を外に出した
let rootVueObj = {
    el: '#container', 
    components: {
        'l-component': componentVueObj
    }
};

// ルートVueインスタンス
// rootVueObjを登録
new Vue(rootVueObj);    

Vueオブジェクトの定義と登録

ここまでの整理で、Vueオブジェクト定義と登録によって成立していることがはっきりしたので、今度はルートVueインスタンス、グローバルコンポーネント、ローカルコンポーネント、それぞれの定義と登録を比較してみる。

定義

// ルートVueインスタンスでのVueオブジェクト記述形式
let vueObj = {
    el: 'DOMセレクタ',
    data: {}
};
// グローバルコンポーネント/ローカルコンポーネントでのVueオブジェクト記述形式
let vueObj = {
    data: function () {
        return {}
    }
    // , template: 'テンプレート'

まず、グローバルコンポーネントとローカルコンポーネントのVueオブジェクトは全く同じである。ルートVueインスタンスは全く同じでは無いが、かなり似ている(templateオプションについては、後で触れます)。

登録

// ルートVueインスタンスでのVueオブジェクトの登録
new Vue(rootVueObj);
// グローバルコンポーネントでのVueオブジェクトの登録
Vue.component('g-component', componentVueObj);
// ルートVueインスタンス
new Vue({rootVueObj);
// ローカルコンポーネントでのVueオブジェクトの登録
let rootVueObj = {
    el: '#container', 
    components: {
        'l-component': componentVueObj
    }
};
// ルートVueインスタンス
new Vue(rootVueObj);    

Vueオブジェクトという観点から整理すると、

  • 定義の書き方は2種類
  • 登録方法はルートVueインスタンス、グローバルコンポーネント、ローカルコンポーネントによってそれぞれ異なる

これだけでもかなり見通しがよくなりませんか?

考察

ルートVueインスタンスとコンポーネントの違い

elオプション

ルートVueインスタンスとコンポーネントの大きな違いはHTML要素へ紐付けする際の対象の違い。ルートVueインスタンスは'#container'という既存のHTML要素id属性で紐付けしている。それに対して、グローバルコンポーネントの'g-component'もローカルコンポーネントの'l-component'カスタムタグへの紐付けである。Vue独自ルールであるカスタムタグは素のHTMLのままでは使用することはできない。そのため既存のHTML要素の接点としてルートVueインスタンスが存在している。そう考えると、ルートVueインスタンスにだけ'elオプション'がある理由が理解できる(唯一の例外は el のようなルート固有のオプションです)。

dataオプション

ルートVueインスタンスでは直接文字列や数値が入るのに対し、コンポーネントでは関数経由でそれらを指定する。その理由はインスタンスごとの値を保持するためということだが(data は関数でなければなりません)、関数にするとなぜそれが可能なのかはわからない(何となくはわかる気もするが、、)。誰か教えていただけると嬉しい。

templateオプション

templateオプションはルートVueインスタンスに登録するVueオブジェクトにも記述できる(あまりそういう書き方をは目にしないが、、)。なので、実はこの点に関しては両者に違いはない。
逆に、本記事のようような書き方をする場合、HTML側ににテンプレートの内容を書くことはできない。X-テンプレートを使うとできるようなので、気になる人はそちらを試してみると良いかもしれない(X- テンプレート)。
X-テンプレートの他には、単一ファイルコンポーネントという形式でVueオブジェクトからテンプレートの記述を分割できる。プロジェクトがある程度大きくなれば単一ファイルコンポーネントを使うことが必須になるはず。本記事では触れないけれども、本記事の内容が理解の助けになると思う(そもそも、それが本記事の目的の一つ)。

グローバルコンポーネントとローカルコンポーネントの違い

両者の違いは名前通りグローバルとローカルの違いだが、それは記述にも表れている。グローバルコンポーネントの登録は直接カスタムタグの名前が紐付けられている。それに対し、ローカルコンポーネントの登録はルートVueインスタンス(親)のcomponentsオブションに対してである(親VueオブジェクトはルートVueインスタンスである必要はない)。これによってローカル化を実現している。
違いではなく共通点に目を向けると、どちらもルートVueインスタンスで紐付けされたHTML要素<div id='container'>)のなかで、コンポーネントのカスタムDOMが記述されている。繰り返しになるが、ルートVueインスタンスは既存のHTML要素の接点なので、グローバルコンポーネントであってもその外には出られない。

38
31
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
38
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?