一、前言
上一篇体验了拆组件的爽,这篇补全"手续":.vue 文件放哪、怎么引入、怎么起名,以及懒人终极方案------unplugin-vue-components 自动导入(写标签不写 import)。同时把命名规范一次说清,避免后面 15 篇的案例里命名来回横跳。
二、创建一个组件:就是一个 .vue 文件
组件 = 单文件组件(SFC),在 src/components/ 下新建 MyButton.vue:
vue
<!-- src/components/MyButton.vue -->
<template>
<button class="my-btn" @click="count++">
点了 {{ count }} 次
</button>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<style scoped>
.my-btn {
padding: 6px 16px;
background: #42b983;
color: #fff;
border: none;
border-radius: 4px;
}
</style>
文件名即组件名,两条硬规范:
- 用大驼峰(PascalCase) :
MyButton.vue✅,my-button.vue❌(部分系统大小写不敏感,会埋雷) - 多单词 :
MyButton而不是Button(防止和原生/内置组件重名)
三、使用组件:import + 写标签
在任意页面(如 App.vue)里三步走:
vue
<template>
<!-- 3. 像用原生标签一样使用 -->
<MyButton />
<MyButton />
<MyButton />
<!-- kebab-case 写法也可以,两者等价 -->
<my-button />
</template>
<script setup>
// 1. 导入组件(script setup 里导入即注册,不需要 components 选项)
import MyButton from './components/MyButton.vue'
</script>
对比 Vue2 的选项式写法(了解即可):
js
// Vue2/Vue3 选项式:导入后还要手动注册
export default {
components: { MyButton }
}
<script setup> 最大的便利之一:导入即注册 ,少写一行 components。三个 <MyButton /> 各自有独立 count(023 篇说的状态隔离,眼见为实)。
【截图位置:三个按钮计数互不干扰的运行效果】
四、组件嵌套:组件里用组件
组件可以无限层嵌套,每层就是"import + 使用"的重复:
vue
<!-- src/components/UserCard.vue -->
<template>
<div class="card">
<h4>{{ name }}</h4>
<p>{{ bio }}</p>
<MyButton /> <!-- 嵌套使用 MyButton -->
</div>
</template>
<script setup>
import MyButton from './MyButton.vue'
defineProps({
name: String,
bio: String
})
</script>
嵌套层级建议控制在 3-4 层内,过深的嵌套(套娃)是组件设计有问题的信号。
五、懒人方案:unplugin-vue-components 自动导入
每个组件都要 import 一遍,页面一多 import 区全是组件名。官方生态的自动导入插件解决它:
1. 安装
bash
npm i -D unplugin-vue-components
2. 配置 vite.config.js
js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import Components from 'unplugin-vue-components/vite'
export default defineConfig({
plugins: [
vue(),
Components() // 加这一行
]
})
3. 直接用,不写 import
vue
<template>
<!-- 无需 import MyButton,插件编译时自动帮你补上 -->
<MyButton />
</template>
工作原理:编译时插件扫描模板里的标签,在默认的 src/components/ 目录下找到同名组件,自动生成 import 语句。本质还是局部导入,只是手写部分被插件代劳了。
三个实用细节:
- 默认只扫
src/components/,其他目录要配dirs选项:Components({ dirs: ['src/components', 'src/business'] }) - 它还能配合 Element Plus 等库做"按需自动导入"(064 篇实战)
- 改了 vite.config.js 记得重启 dev 服务器(003 篇的老规矩)
【截图位置:不写 import 直接使用组件且正常渲染的效果】
六、全局注册:什么时候用
除了局部导入,还可以全局注册------一次注册,任何地方直接用:
js
// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import MyButton from './components/MyButton.vue'
createApp(App)
.component('MyButton', MyButton) // 全局注册
.mount('#app')
vue
<!-- 任何组件里直接用,不用 import -->
<MyButton />
但全局注册是把双刃剑 :组件没被使用也会被打进包(影响体积),且看代码时不知道组件从哪来。实际项目约定:业务组件一律局部导入/自动导入,只有极少数基础组件(如全局 Loading)才全局注册。
七、踩坑记录
- 组件名和标签大小写 :
import MyButton后写<mybutton />❌------多单词组件必须 PascalCase 或 kebab-case,不能全小写粘连 - 自动导入不生效 :先重启 dev;确认组件在默认目录
src/components/里;标签名和文件名拼写一致 - 自动导入与手动 import 混用报"重复注册":同一个组件二选一,别既 import 又让插件处理
- 循环引用:A 导入 B、B 又导入 A 会报错,说明组件职责划分出了问题,把公共部分抽成第三个组件
- style scoped 别忘了:子组件样式不写 scoped 会污染全局------同类名按钮全被带偏
八、今日小结
- 组件 =
src/components/下的 PascalCase 多单词 .vue 文件 <script setup>导入即注册;标签用 PascalCase 或 kebab-case- unplugin-vue-components 自动导入:插件替你写 import,本质仍是局部注册
- 全局注册慎用:只有极少数基础组件配得上
下篇预告
组件活下来了,该"说话"了。第一对通信 API:props 父传子------单向数据流为什么"数据只能往下流"?子组件为什么不能改 props?下一篇 025 讲透。