组件注册
一个 Vue 组件在使用前需要先被“注册”,这样 Vue 才能在渲染模板时找到其对应的实现。组件注册有两种方式:全局注册和局部注册。
全局注册
我们可以使用 Vue 应用实例的 .component() 方法,让组件在当前 Vue 应用中全局可用。
- 语法:Vue.component(‘组件名称’, 组件配置对象)
- 具体使用
- 在main.ts中 引入
// 引入全局组件
import { setupGlobComp } from '@/components'
setupGlobComp(app)
- components/index.ts中
import type { App } from 'vue'
import teleportTest from './test/teleportTest.vue'
import MyModal from './test/MyModal.vue'
export const setupGlobComp = (app: App<Element>) => {
app.component('teleportTest', teleportTest)
app.component('MyModal', MyModal)
}
- 全局注册的组件可以在此应用的任意组件的模板中使用
<teleportTest />
<MyModal />
局部注册
全局注册虽然很方便,但有以下几个问题:
-
全局注册,但并没有被使用的组件无法在生产打包时被自动移除 (也叫“tree-shaking”)。如果你全局注册了一个组件,即使它并没有被实际使用,它仍然会出现在打包后的 JS 文件中。
-
全局注册在大型项目中使项目的依赖关系变得不那么明确。在父组件中使用子组件时,不太容易定位子组件的实现。和使用过多的全局变量一样,这可能会影响应用长期的可维护性。
相比之下,局部注册的组件需要在使用它的父组件中显式导入,并且只能在该父组件中使用。它的优点是使组件之间的依赖关系更加明确,并且对 tree-shaking 更加友好。
- 在使用 <script setup> 的单文件组件中,导入的组件可以直接在模板中使用,无需注册:
<script setup>
import ComponentA from './ComponentA.vue'
</script>
<template>
<ComponentA />
</template>
如果没有使用 <script setup>,则需要使用 components 选项来显式注册:
import ComponentA from './ComponentA.js'
export default {
components: {
ComponentA
},
setup() {
// ...
}
}
组件名格式
- PascalCase
Vue 推荐使用 PascalCase(首字母大写的骆驼拼写法)来命名组件。这种方式在 JavaScript 中定义和引用组件时更为直观。
// 定义组件
const MyComponent = {
template: '<div>My Component</div>'
};
// 注册组件
app.component('MyComponent', MyComponent);
<!-- 在模板中使用 -->
<MyComponent />
- kebab-case
在模板中,Vue 允许使用 kebab-case(短横线分隔)来引用组件,这种方式在 HTML 中更为常见。
<!-- 在模板中使用 -->
<my-component></my-component>
但需要注意的是,在 JavaScript 中定义和注册组件时,仍需使用 PascalCase。Vue 会自动将 kebab-case 转换为 PascalCase 来查找组件。
总结
- 全局注册:使用 createApp 的 component 方法在 Vue 应用的全局范围内注册组件。
- 局部注册:在单个组件的 components 选项中注册组件,使其仅在该组件及其子组件中可用。
- 组件名格式:推荐使用 PascalCase 定义和注册组件,在模板中可以使用 kebab-case 引用组件。
动态注册组件
动态注册组件允许你在运行时根据需要注册组件,这在构建复杂的单页面应用时非常有用。
import { createApp, defineComponent } from 'vue';
const app = createApp({});
// 动态注册组件
function registerComponent(name, component) {
app.component(name, component);
}
// 定义一个组件
const MyDynamicComponent = defineComponent({
template: '<div>Dynamic Component</div>'
});
// 注册组件
registerComponent('MyDynamicComponent', MyDynamicComponent);
app.mount('#app');
import.meta.glob() 全局注册组件
// plugins/index.ts
import type { App } from 'vue';
// 动态导入 components 目录下的所有 .vue
const components = import.meta.glob<Record<string, any>>('../components/*/**.vue');
export const setupGlobComp2 = (app: App<Element>) => {
console.log(components,'aaaaa');
for (const [path, component] of Object.entries(components)) {;
// const componentName = path
const componentName = path
.split('/')
.pop()
.replace(/\.\w+$/, ''); // 移除文件扩展名
// 1.注册组件
component().then((module) => {
app.component(componentName, module.default);
});
// 2.注册组件
// app.component(componentName,component);
}
}
在main.ts中 引入
// 引入全局组件
import { setupGlobComp2 } from '@/plugins'
setupGlobComp2(app)
// 在组件中使用
<MyDynamicComponent />