はじめに
オブジェクトリテラルの観点で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要素の接点なので、グローバルコンポーネントであってもその外には出られない。