为什么需要注册组件?
当在Vue项目中定义了一个新的组件后,要想在其他组件中引用这个新的组件,需要对新的组件进行注册。在注册组件的时候,需要给组件取一个名字,从而区分每个组件,可以采用帕斯卡命名法(PascalCase)为组件命名。
Vue提供了两种注册组件的方式,分别是全局注册和局部注册。
1. 全局注册
在实际开发中,如果某个组件的使用频率很高,许多组件中都会引用该组件,则推荐将该组件全局注册。被全局注册的组件可以在当前Vue项目的任何一个组件内引用。
在Vue项目的src\main.js文件中,通过Vue应用实例的component()方法可以全局注册组件,该方法的语法格式如下。
component('组件名称', 需要被注册的组件)
上述语法格式中,component()方法接收两个参数,第1个参数为组件名称,注册完成后即可全局使用该组件名称,第2个参数为需要被注册的组件。
在src\main.js文件中注册一个全局组件MyComponent,示例代码如下。
import { createApp } from 'vue';
import './style.css'
import App from './App.vue'
import MyComponent from './components/MyComponent.vue'
const app = createApp(App)
app.component('MyComponent', MyComponent)
app.mount('#app')
component()方法支持链式调用,可以连续注册多个组件,示例代码如下。
app.component('ComponentA', ComponentA)
.component('ComponentB', ComponentB)
.component('ComponentC', ComponentC)
2. 局部注册
在实际开发中,如果某些组件只在特定的情况下被用到,推荐进行局部注册。局部注册即在某个组件中注册,被局部注册的组件只能在当前注册范围内使用。
局部注册组件的示例代码如下。
<script>
import ComponentA from './ComponentA.vue'
export default {
components: { ComponentA: ComponentA }
}
</script>
在使用setup语法糖时,导入的组件会被自动注册,无须手动注册,导入后可以直接在模板中使用,示例代码如下。
<script setup>
import ComponentA from './ComponentA.vue'
</script>
将组件注册完成后,若要将组件在页面中渲染出来,需要引用组件。
在组件的<template>标签中可以引用其他组件,被引用的组件需要写成标签的形式,标签名应与组件名对应。组件的标签名可以使用短横线分隔或帕斯卡命名法命名。例如,<my-component>标签和<MyComponent>标签都表示引用MyComponent组件。一个组件可以被引用多次,但不可出现自我引用和互相引用的情况,否则会出现死循环。
演示组件的使用方法
<template>
<h5>父组件</h5>
<div class="box">
</div>
</template>
<style>
.box {
display: flex;
}
</style>
创建src\components\GlobalComponent.vue文件,表示全局组件。
<template>
<div class="global-container"><h5>全局组件</h5></div>
</template>
<style>
.global-container {
border: 1px solid black;
height: 50px;
flex: 1;
}
</style>
创建src\components\LocalComponent.vue文件,表示局部组件。
<template>
<div class="local-container">
<h5>局部组件</h5>
</div>
</template>
<style>
.local-container {
border: 1px dashed black;
height: 50px;
flex: 1;
}
</style>
修改src\main.js文件,导入GlobalComponent组件并调用component()方法全局注册GlobalComponent组件。
import { createApp } from 'vue'
import './style.css'
import App from './components/ComponentUse.vue'
import GlobalComponent from './components/GlobalComponent.vue'
const app = createApp(App)
app.component('GlobalComponent', GlobalComponent)
app.mount('#app')
修改src\components\ComponentUse.vue文件,添加代码导入LocalComponent组件。
<script setup>
import LocalComponent from './LocalComponent.vue'
</script>
修改src\components\ComponentUse.vue文件,在class为box的<div>标签中引用GlobalComponent组件和LocalComponent组件。
<div class="box">
<GlobalComponent />
<LocalComponent />
</div>
在默认情况下,写在Vue组件中的样式会全局生效,很容易造成多个组件之间的样式冲突问题。
例如,为ComponentUse组件中的h5元素添加边框样式,具体代码如下。
h5 {
border: 1px dotted black;
}
保存上述代码后,在浏览器中访问http://127.0.0.1:5173/,添加边框样式后的页面效果如下图所示。

从上图可以看出,ComponentUse组件、GlobalComponent组件和LocalComponent组件中h5元素的边框样式都发生了改变,但是代码中只有ComponentUse组件设置了边框样式效果,说明组件之间存在样式冲突。
为什么组件之间会产生样式冲突?
导致组件之间样式冲突的根本原因是:在单页Web应用中,所有组件的DOM结构都是基于唯一的index.html页面进行呈现的。每个组件中的样式都可以影响整个页面中的DOM元素。
在Vue中可以使用scoped属性和深度选择器来解决组件之间的样式冲突。
1. scoped属性
Vue为<style>标签提供了scoped属性,用于解决组件之间的样式冲突。
为<style>标签添加scoped属性后,Vue会自动为当前组件的DOM元素添加一个唯一的自定义属性(如data-v-7ba5bd90),并在样式中为选择器添加自定义属性(如.list[data-v-7ba5bd90]),从而限制样式的作用范围,防止组件之间的样式冲突问题。
下面演示scoped属性的使用。
修改ComponentUse组件,为<style>标签添加scoped属性,具体代码如下。
<style scoped>
保存上述代码后,在浏览器中访问http://127.0.0.1:5173/,在<style>标签中添加scoped属性的页面效果如下图所示。

打开开发者工具,切换到Elements面板,查看父组件的h5元素的代码,如下图所示。

从上图可以看出,当<style>标签添加scoped属性后,h5元素和相应的选择器被Vue自动添加了data-v-e4f30916属性,从而解决了样式冲突的问题。
2. 深度选择器
如果给当前组件的<style>标签添加了scoped属性,则当前组件的样式对其子组件是不生效的。
如果在添加了scoped属性后还需要让某些样式对子组件生效,则可以使用深度选择器来实现。
深度选择器通过:deep()伪类来实现,在其小括号中可以定义用于子组件的选择器,例如,“:deep(.title)”被编译之后生成选择器的格式为“[data-v-7ba5bd90] .title”。
演示如何通过ComponentUse组件更改LocalComponent组件的样式
为LocalComponent组件的h5元素添加class属性。
<h5 class="title">局部组件</h5>
在ComponentUse组件中定义.title的样式。
:deep(.title){
border: 3px dotted black;
}