Appearance
什么是组件?
组件是 Vue 的核心概念。把页面拆成一个个独立、可复用的小块,每个小块就是一个组件。
页面 = 拼积木
┌──────────────────────────────┐
│ Header(顶部导航组件) │
├──────────────────────────────┤
│ Main(主要内容区组件) │
├──────────────────────────────┤
│ Footer(底部组件) │
└──────────────────────────────┘
每个组件就是一个 .vue 文件,封装了 HTML、JavaScript 和 CSS。
单文件组件(SFC)的结构
vue
<template>
<!-- 这个组件的 HTML -->
</template>
<script>
// 这个组件的 JavaScript 逻辑
</script>
<style scoped>
/* 这个组件的 CSS 样式 */
</style>
组件嵌套关系
Vue 应用本质上是一棵组件树——一个组件里放另一个组件,层层嵌套。
App.vue(根组件)
├── Header.vue(顶部导航)
├── Main.vue(主内容区)
│ ├── Article.vue(文章卡片)
│ └── Article.vue(文章卡片...复用多次)
└── Footer.vue(底部)
父组件写法
vue
<template>
<div class="layout">
<Header />
<Main />
<Aside />
</div>
</template>
<script>
import Header from './components/Header.vue'
import Main from './components/Main.vue'
import Aside from './components/Aside.vue'
export default {
components: { Header, Main, Aside }
}
</script>
三个步骤:import 导入 → components 注册 → <template> 中使用。
数据流向:从上到下
数据从父组件流向子组件,从根往叶子流。父组件通过 props 把数据传给子组件,子组件不能直接改父组件的数据——这是 Vue 的核心设计原则。
组件注册方式
局部注册(推荐)
只在当前组件内可用:
vue
<template>
<MyButton />
</template>
<script>
import MyButton from './MyButton.vue'
export default {
components: { MyButton }
}
</script>
优点:依赖关系清晰,支持 tree-shaking,好维护。
全局注册
在 main.js 中注册,整个应用任何地方都能用:
javascript
import { createApp } from 'vue'
import App from './App.vue'
import MyButton from './components/MyButton.vue'
const app = createApp(App)
app.component('MyButton', MyButton)
app.mount('#app')
缺点:main.js 会越来越臃肿,无法 tree-shaking。
| 场景 | 用哪种 |
|---|---|
| 通用组件(按钮、弹窗...到处用) | 全局注册 |
| 特定页面的组件 | 局部注册 |
| 不确定是否会复用 | 先局部,需要时再提升 |
💡 Tip:先用局部注册,等这个组件确实在 3 个以上地方被引用了,再考虑全局注册。
<slot> — 预留的"内容洞"
组件里的 <slot> 就像是一个"占位符":
vue
<!-- MyCard.vue -->
<template>
<div class="card">
<slot></slot> <!-- 默认插槽 -->
<slot name="footer"></slot> <!-- 具名插槽 -->
</div>
</template>
vue
<!-- 使用时 -->
<MyCard>
<p>这是卡片的内容</p>
<template v-slot:footer>
<button>查看详情</button>
</template>
</MyCard>
scoped — 组件样式隔离
vue
<style scoped>
.title { color: red; } /* 只影响本组件内的 .title */
</style>
不加 scoped = 全局样式 = 影响整个应用。开发时默认加 scoped 是个好习惯。
组件命名规范
- 用多个单词:
MyButton而不是Button(避免冲突) - PascalCase:
MyButton、UserProfile - 模板中
<MyButton />或<my-button></my-button>都行