Appearance
组件介绍 👌
要点速览
- 单文件组件(SFC)由模板、逻辑、样式三部分组成。
<script setup>更简洁,自动向模板暴露变量与组件。- 注册方式:全局注册适合基础/通用组件;业务组件推荐局部注册。
- 样式作用域:
<style scoped>仅影响当前组件;跨组件样式穿透用:deep()伪类。 - 组件名推荐大驼峰;原生 DOM 模板中必须使用短横线命名。
- 组件三大核心:Props、事件(emit)、插槽;是组件通信与扩展的关键。
组件结构
在 Vue 中支持单文件组件(SFC),一个文件对应一个组件(后缀 .vue)。组件包含模板、逻辑与样式三部分:
vue
<template>
<button @click="count++">Count is: {{ count }}</button>
<p>这是一段组件内部的内容</p>
<!-- 可以有多个根节点(Vue 3) -->
<span>Another root</span>
</template>
<script setup>
import { ref } from "vue";
const count = ref(0);
</script>
<style scoped>
button {
padding: 15px;
}
</style>setup 语法糖的优势
- 无需
return暴露变量与方法,模板可直接使用。 - 更佳的类型推断与 IDE 体验(TS 友好)。
- 支持顶级
await,简化异步初始化逻辑。 - 少模板代码(boilerplate),更易读更易维护。
如果你仍使用传统 Options API,也完全兼容:
vue
<script>
import { ref } from "vue";
export default {
setup() {
const count = ref(0);
function add() {
count.value++;
}
return { count, add };
},
};
</script>样式作用域要点
scoped会为当前组件的元素添加独特属性选择器,样式不外泄。- 想影响子组件内部结构时,使用
:deep(.child)进行穿透。 - 设计系统/全局主题请放到全局样式或 CSS 变量中。
除了 .vue 文件,也可以使用对象形式定义组件(适合示例或简单场景):
js
export default {
setup() {
const count = ref(0);
return { count };
},
template: `<div>{{ count }}</div>`,
};在原生 DOM 模板中(例如挂到 <template id="..."> 的字符串模板),同样可以使用:
html
<template id="my-template-element">
<div>
<h1>{{ count }}</h1>
<button @click="count++">Increment</button>
</div>
<!-- 注意:此处是原生 DOM 模板 -->
</template>
<script>
const { createApp, ref } = Vue;
const App = {
setup() {
const count = ref(0);
return { count };
},
template: "#my-template-element",
};
createApp(App).mount("#app");
</script>组件注册
组件注册分为两种:全局注册 与 局部注册。
全局注册
使用应用实例的 app.component() 方法进行全局注册,注册后在任意组件内都可用:
js
import { createApp } from "vue";
import MyComponent from "./App.vue";
const app = createApp({});
app.component("MyComponent", MyComponent);
// 支持链式调用
app
.component("ComponentA", ComponentA)
.component("ComponentB", ComponentB)
.component("ComponentC", ComponentC);不要滥用全局注册
- 难以进行 tree-shaking,打包体积增大。
- 组件依赖关系不清晰,降低维护性与可读性。
- 名称冲突风险更高(大型项目)。
局部注册(推荐)
在使用组件的文件中显式引入并注册,更利于依赖管理与体积优化:
vue
<template>
<button @click="add">Count is: {{ count }}</button>
<TestCom />
</template>
<script>
import { ref } from "vue";
import TestCom from "./components/TestCom.vue";
export default {
components: { TestCom },
setup() {
const count = ref(0);
function add() {
count.value++;
}
return { count, add };
},
};
</script>在 <script setup> 中更简单,导入即用(自动注册到模板):
vue
<template>
<button @click="add">Count is: {{ count }}</button>
<TestCom />
</template>
<script setup>
import { ref } from "vue";
import TestCom from "./components/TestCom.vue";
const count = ref(0);
function add() {
count.value++;
}
</script>推荐实践
- UI 库或极通用的基础组件可考虑全局注册(如
BaseButton)。 - 业务组件保持局部注册,清晰展现依赖关系,利于按需打包。
组件名
推荐使用 大驼峰(PascalCase) 作为组件名,例如:UserCard、TaskList。
模板中的大小写差异
- 在单文件组件模板中,
<UserCard />与<user-card />都可使用。 - 在原生 DOM 模板或字符串模板中,只能使用短横线命名:
<user-card></user-card>。
示例:
html
<!-- 单文件组件模板中:两种写法均可 -->
<UserCard />
<user-card />
<!-- 原生 DOM 模板(如通过字符串 template 挂载):只能短横线 -->
<user-card></user-card>常见误区与排查
常见误区
- 在
<script setup>中未导入子组件却直接在模板使用,导致组件未定义错误。 - 在
scoped样式中直接选择子组件内部元素,样式不生效;需要:deep()深度选择器伪类。 - 全局注册后使用 PascalCase 组件名在原生模板中不生效;应改为短横线。
:deep() 使用示例
vue
<style scoped>
.card {
border: 1px solid #eee;
}
/* 影响子组件内部元素 */
:deep(.child-title) {
font-weight: bold;
}
</style>小结与后续
组件在应用层面,有三个核心知识点:
- Props(父 → 子传递数据)
- 自定义事件(子 → 父反馈与通信)
- 插槽(结构与内容扩展)
学习建议
- 先掌握 SFC 结构、
<script setup>与局部注册。 - 随后系统学习 Props、事件与插槽,理解组件通信与扩展模式。
- 最后关注样式作用域与跨组件样式组织,提升可维护性。
