定义好组件后,需要注册才能使用。Vue 提供了两种注册方式:全局注册和局部注册。选择哪种方式,取决于组件的使用范围和项目规模。
使用 Vue.component() 注册的组件是全局组件,可以在任何 Vue 实例的模板中使用。
// 注册全局组件
Vue.component('my-component', {
template: '<div>全局组件</div>'
})
// 创建 Vue 实例
new Vue({
el: '#app'
})
<div id="app">
<my-component></my-component>
</div>
全局组件可以在任何地方使用,包括其他组件内部:
Vue.component('component-a', {
template: '<div>组件 A</div>'
})
Vue.component('component-b', {
template: `
<div>
<p>组件 B</p>
<component-a></component-a>
</div>
`
})
new Vue({
el: '#app',
template: `
<div>
<component-a></component-a>
<component-b></component-b>
</div>
`
})
适合全局注册的组件:
全局注册的问题:
使用组件的 components 选项注册局部组件,只能在当前组件中使用。
// 定义组件
var ComponentA = {
template: '<div>组件 A</div>'
}
var ComponentB = {
template: '<div>组件 B</div>'
}
// 在 Vue 实例中局部注册
new Vue({
el: '#app',
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})
<div id="app">
<component-a></component-a>
<component-b></component-b>
</div>
var ComponentA = {
template: '<div>组件 A</div>'
}
var ComponentB = {
template: `
<div>
<p>组件 B</p>
<component-a></component-a>
</div>
`,
components: {
'component-a': ComponentA
}
}
实际项目中,通常使用 ES6 模块:
// ComponentA.js
export default {
template: '<div>组件 A</div>'
}
// ComponentB.js
import ComponentA from './ComponentA.js'
export default {
template: `
<div>
<p>组件 B</p>
<component-a></component-a>
</div>
`,
components: {
ComponentA
}
}
ES6 简写语法
当组件名与变量名相同时,可以简写:
components: {
ComponentA // 等同于 ComponentA: ComponentA
}
Vue 会自动将 ComponentA 转换为 component-a 使用。
适合局部注册的组件:
局部注册的好处:
| 特性 | 全局注册 | 局部注册 |
|---|---|---|
| 使用范围 | 所有 Vue 实例 | 当前组件 |
| 打包体积 | 全部打包 | 按需打包 |
| 命名冲突 | 容易冲突 | 不会冲突 |
| 依赖关系 | 不明确 | 明确 |
| 适用组件 | 基础、通用组件 | 业务、页面组件 |
// utils/register-components.js
import Vue from 'vue'
import AppButton from './components/AppButton.vue'
import AppInput from './components/AppInput.vue'
import AppIcon from './components/AppIcon.vue'
import AppLoading from './components/AppLoading.vue'
// 批量注册基础组件
const baseComponents = {
AppButton,
AppInput,
AppIcon,
AppLoading
}
Object.keys(baseComponents).forEach(key => {
Vue.component(key, baseComponents[key])
})
// main.js
import Vue from 'vue'
import './utils/register-components'
import App from './App.vue'
new Vue({
render: h => h(App)
}).$mount('#app')
<template>
<div class="user-page">
<user-header :user="user"></user-header>
<user-profile :user="user"></user-profile>
<user-posts :posts="posts"></user-posts>
</div>
</template>
<script>
import UserHeader from './UserHeader.vue'
import UserProfile from './UserProfile.vue'
import UserPosts from './UserPosts.vue'
export default {
components: {
UserHeader,
UserProfile,
UserPosts
},
data() {
return {
user: {},
posts: []
}
}
}
</script>
对于大量基础组件,可以使用自动化注册:
// utils/register-components.js
import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'
// 查找所有 .vue 文件
const requireComponent = require.context(
'./components/base',
false,
/Base[A-Z]\w+\.(vue|js)$/
)
requireComponent.keys().forEach(fileName => {
const componentConfig = requireComponent(fileName)
const componentName = upperFirst(
camelCase(
fileName.replace(/^\.\/(.*)\.\w+$/, '$1')
)
)
Vue.component(componentName, componentConfig.default || componentConfig)
})
这样,components/base 目录下所有 BaseXxx.vue 文件都会自动注册。
在 .vue 文件中,推荐使用局部注册:
<template>
<div>
<app-button @click="handleClick">按钮</app-button>
<app-input v-model="value"></app-input>
</div>
</template>
<script>
import AppButton from '@/components/base/AppButton.vue'
import AppInput from '@/components/base/AppInput.vue'
export default {
name: 'MyComponent',
components: {
AppButton,
AppInput
},
data() {
return {
value: ''
}
},
methods: {
handleClick() {
console.log('clicked')
}
}
}
</script>
局部组件不能在子组件中使用
var ComponentA = {
template: '<div>组件 A</div>'
}
new Vue({
el: '#app',
components: {
'component-a': ComponentA
}
})
// ComponentA 只能在 #app 的模板中使用
// 不能在其他全局组件中使用
如果需要在多个组件中使用,考虑全局注册或在每个组件中分别注册。
组件命名冲突
// 全局组件
Vue.component('my-component', {
template: '<div>全局</div>'
})
// 局部组件
new Vue({
el: '#app',
components: {
'my-component': {
template: '<div>局部</div>'
}
}
})
// 局部组件会覆盖全局组件
组件注册要点: