コンポーネントの登録

最終更新日: 2018年4月26日

このページは コンポーネントの基本 を読まれていることが前提になっています。コンポーネントを扱った事のない場合はこちらのページを先に読んでください。

コンポーネント名

コンポーネントを登録するときは、いつでも名前が与えられます。例えば、グローバル登録の場合:

Vue.component('my-component-name', { /* ... */ })

コンポーネント名は Vue.component の第一引数です。

コンポーネントの命名は、コンポーネントの使用箇所に左右されます。(文字列テンプレート、または単一ファイルコンポーネントではなく) DOM 上で直接コンポーネントを使用する場合は、W3C rules に従ったカスタムタグ名(全て小文字で、ハイフンが含まれていること)を推奨します。これは、既に存在する、そして将来定義される HTML 要素との衝突を防止するのに役立ちます。

スタイルガイドでは、コンポーネント名についてのその他の推奨項目を見ることができます。

命名のケース (Name Casing)

コンポーネント名を定義する時、2 つの選択肢があります:

ケバブケース (kebab-case)

Vue.component('my-component-name', { /* ... */ })

ケバブケースでコンポーネント名を定義する場合、そのカスタム要素を参照する時も同様に、 <my-component-name> のように、ケバブケースを用いなければいけません。

パスカルケース (PascalCase)

Vue.component('MyComponentName', { /* ... */ })

パスカルケースでコンポーネントを定義する場合、そのカスタム要素の参照には、どちらのケースも用いることができます。これは、 <my-component-name><MyComponentName> のどちらも許容されることを意味します。ただし、DOM 内 (すなわち、文字列でないテンプレート) に直接使用する場合には、ケバブケースの名前のみが有効なので注意してください。

グローバル登録

ここまでは Vue.component だけを使ってコンポーネントを作成しました:

Vue.component('my-component-name', {
// ... options ...
})

これらのコンポーネントは グローバル登録 されています。これは、登録後に作成された、全てのルート Vue インスタンス(new Vue)のテンプレート内で使用できることを意味します。例えば:

Vue.component('component-a', { /* ... */ })
Vue.component('component-b', { /* ... */ })
Vue.component('component-c', { /* ... */ })

new Vue({ el: '#app' })
<div id="app">
<component-a></component-a>
<component-b></component-b>
<component-c></component-c>
</div>

これは全てのサブコンポーネントにも適用されます。これら 3 つのコンポーネント全てが 内部で相互に 使用可能になることを意味します。

ローカル登録

多くの場合、グローバル登録は理想的ではありません。例えば Webpack のようなビルドシステムを利用しているときに、グローバルに登録した全てのコンポーネントは、たとえ使用しなくなっても、依然として最終ビルドに含まれてしまうことでしょう。これは、ユーザがダウンロードしなくてはならない JavaScript のファイルサイズを不要に増加させてしまいます。

このような場合に、コンポーネントを素の JavaScript オブジェクトとして定義することができます:

var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }

次に、components オプション内に使いたいコンポーネントを定義します:

new Vue({
el: '#app'
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})

components オブジェクトのそれぞれのプロパティは、キーはカスタム要素の名前になり、一方、値はコンポーネントのオプションオブジェクトを含みます。

ローカル登録されたコンポーネントは、他のサブコンポーネント内では使用できない ことに注意して下さい。例えば、ComponentAComponentB 内で使用可能にしたいときは、このように使う必要があります:

var ComponentA = { /* ... */ }

var ComponentB = {
components: {
'component-a': ComponentA
},
// ...
}

もしくは、Babel と Webpack のようなものを用いて ES2015 モジュールを利用しているならば、このようになるでしょう:

import ComponentA from './ComponentA.vue'

export default {
components: {
ComponentA
},
// ...
}

ES2015+ では ComponentA のような変数名をオブジェクト内部に配置することは ComponentA: ComponentA の省略記法にあたり、変数の名前は次のどちらも意味することに注意して下さい:

モジュールシステム

もし、 import/require を用いたモジュールシステムを使用しないなら、このセクションをスキップすることができます。使用する場合、いくつかの特別な手順とヒントを用意しています。

モジュールシステム内のローカル登録

ここを見ているということは、おそらくあなたは Babel と Webpack のようなものを用いて、モジュールシステムを使用していることでしょう。もしそうなら、それぞれのコンポーネントをファイルとして配置する components ディレクトリを作成することを推奨します。

ローカル登録をする前に、使いたいコンポーネントごとにインポートする必要があります。例えば、ComponentB.js または ComponentB.vue ファイルを仮定して:

import ComponentA from './ComponentA'
import ComponentC from './ComponentC'

export default {
components: {
ComponentA,
ComponentC
},
// ...
}

これで ComponentAComponentC の両方が ComponentB のテンプレート内で使えるようになります。

基底コンポーネントの自動グローバル登録

コンポーネントのうち多くは比較的共通して、 input や button のような要素をラップするだけです。時にこれらを 基底コンポーネント と呼び、これらは複数のコンポーネントを横断して頻繁に用いられます。

多数のコンポーネントが多数の基底コンポーネントを含めた結果:

import BaseButton from './BaseButton.vue'
import BaseIcon from './BaseIcon.vue'
import BaseInput from './BaseInput.vue'

export default {
components: {
BaseButton,
BaseIcon,
BaseInput
}
}

テンプレートでは、比較的少ないマークアップをサポートします:

<BaseInput
v-model="searchText"
@keydown.enter="search"
/>
<BaseButton @click="search">
<BaseIcon name="search"/>
</BaseButton>

幸いにも、Webpack (または 内部的に Webpack を利用している Vue CLI 3+ ) を使用しているなら、 このような非常に汎用的な基底コンポーネントのグローバル登録に require.context を用いることができます。次に示す例は、アプリケーションのエントリファイル(例: src/main.js )で、基底コンポーネントをグローバルにインポートするコードです:

import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'

const requireComponent = require.context(
// コンポーネントフォルダの相対パス
'./components',
// サブフォルダ内を調べるかどうか
false,
// 基底コンポーネントのファイル名に一致させるのに使う正規表現
/Base[A-Z]\w+\.(vue|js)$/
)

requireComponent.keys().forEach(fileName => {
// コンポーネント設定を取得する
const componentConfig = requireComponent(fileName)

// コンポーネント名をパスカルケース (PascalCase) で取得する
const componentName = upperFirst(
camelCase(
// 先頭の `'./` と拡張子をファイル名から取り除く
fileName.replace(/^\.\/(.*)\.\w+$/, '$1')
)
)

// コンポーネントをグローバル登録する
Vue.component(
componentName,
// `export default` を使ってコンポーネントがエクスポートされた場合に存在する
// `.default` でコンポーネントオプションを期待していて
// 存在しない場合にはモジュールのルートにフォールバックします。
componentConfig.default || componentConfig
)
})

(new Vue を使って)ルート Vue インスタンスを作成するより前に、グローバル登録を行う必要があることを 覚えておいてください。この例は実際のプロジェクトの文脈における、このパターンの一例です。