🔥从0到1实战:基于Vue3+TypeScript+Vite开发通用组件库(Element3复刻版)
组件库是中大型前端项目的核心基建,一套设计统一、可复用的组件库能大幅提升开发效率。
本文将手把手带你复刻Element3的核心思路,基于Vue3+TypeScript+Vite技术栈,从环境搭建、规范约束到布局组件开发,完整实现一套可扩展的通用组件库。
一、技术栈与核心思路
1. 核心技术栈
- 构建工具:Vite(极速热更新,适配Vue3+TS)
- 语言:TypeScript(类型约束,提升组件健壮性)
- 样式:Sass(BEM规范封装,统一样式管理)
- 规范工具:husky(Git钩子,约束提交规范)
- 参考模板:Element3(Vue3版Element UI)
2. 组件库核心分类
组件库的组件可按功能划分为四大类,覆盖绝大部分业务场景:
- 基础组件:布局、色彩、字体、图标(无复杂交互,负责页面基础样式)
- 表单组件:输入框、滑块、评分(管理用户输入,核心是输入校验)
- 数据组件:表格、树形控件(展示后台数据)
- 通知组件:弹窗、警告(反馈用户操作状态)
二、环境搭建:从Vite初始化到提交规范约束
1. 创建Vite+Vue3+TS项目
首先初始化基础项目,模板选择vue-ts,快速搭建Vue3+TS开发环境:
npm init vite@latest
# 选择vue-ts模板,完成项目创建
cd 项目名
npm install
2. 配置husky:约束代码提交规范
团队开发中,统一的提交规范和代码格式能大幅降低维护成本,我们用husky实现Git钩子校验。
步骤1:安装并初始化husky
# 安装husky为开发依赖
npm install -D husky
# 初始化husky,生成.husky目录
npx husky install
步骤2:配置commit-msg钩子(校验提交信息)
新增commit-msg钩子,提交代码时校验commit信息格式:
npx husky add .husky/commit-msg "node scripts/verifyCommit.js"
创建scripts/verifyCommit.js文件,编写校验逻辑(参考Vue3提交规范):
const msg = require('fs')
.readFileSync('.git/COMMIT_EDITMSG', 'utf-8')
.trim()
// 校验规则:type(scope): desc(长度1-50)
const commitRE = /^(revert: )?(feat|fix|docs|dx|style|refactor|perf|test|workflow|build|ci|chore|types|wip|release)(\\(.+\\))?: .{1,50}/
// 兼容合并分支的提交信息
const mergeRe = /^(Merge pull request|Merge branch)/
if (!commitRE.test(msg)) {
if(!mergeRe.test(msg)){
console.log('git commit信息校验不通过')
console.error(`git commit的信息格式不对, 需要使用 title(scope): desc的格式
比如 fix: 修复按钮点击无响应bug
feat(container): 新增布局容器组件
`)
process.exit(1)
}
}else{
console.log('git commit信息校验通过')
}
步骤3:配置pre-commit钩子(ESLint校验)
提交代码前先执行ESLint,确保代码格式符合规范:
npx husky add .husky/pre-commit "npm run lint"
至此,提交代码时会先执行ESLint校验,再校验commit信息格式,全部通过才能提交,这也是Vue、Element等开源项目的通用规范。
三、核心实战:开发Element3同款布局组件
布局组件是组件库的基础,我们实现Container、Header、Footer、Aside、Main五个核心布局组件,复刻Element3的布局逻辑。
1. Sass BEM规范封装:统一样式管理
Element3的样式采用BEM规范,前缀统一为el-,我们用Sass的Mixin封装通用逻辑,避免重复代码。
在src/styles下新建mixin.scss:
// 命名空间(统一前缀)
$namespace: 'el';
// 状态前缀(如is-vertical)
$state-prefix: 'is-';
// 封装block:生成.el-xxx类名
@mixin b($block) {
$B: $namespace + '-' + $block !global;
.#{$B} {
@content;
}
}
// 封装state:生成.el-xxx.is-xxx类名
@mixin when($state) {
@at-root {
&.#{$state-prefix + $state} {
@content;
}
}
}
2. 实现Container组件(核心布局容器)
Container是外层容器,逻辑:包含Header/Footer则垂直布局,否则水平布局。
在src/components/container下新建Container.vue:
<template>
<section
class="el-container"
:class="{ 'is-vertical': isVertical }"
>
<slot />
</section>
</template>
<!– 单独的script标签:设置组件name(setup语法无法直接设置) –>
<script lang="ts">
export default {
name: 'ElContainer'
}
</script>
<!– setup语法:TS类型约束+逻辑实现 –>
<script setup lang="ts">
import { useSlots, computed, VNode, Component } from 'vue'
// 定义Props类型
interface Props {
direction?: string
}
const props = defineProps<Props>()
// 获取插槽内容
const slots = useSlots()
// 计算属性:判断是否垂直布局
const isVertical = computed(() => {
if (slots && slots.default) {
// 检测子组件是否包含ElHeader/ElFooter
return slots.default().some((vn: VNode) => {
const tag = (vn.type as Component).name
return tag === 'ElHeader' || tag === 'ElFooter'
})
} else {
// 手动指定direction为vertical则垂直布局
return props.direction === 'vertical'
}
})
</script>
<style lang="scss">
@import '../styles/mixin';
@include b(container) {
display: flex;
flex-direction: row;
flex: 1;
flex-basis: auto;
box-sizing: border-box;
min-width: 0;
// 垂直布局样式
@include when(vertical) {
flex-direction: column;
}
}
</style>
3. 实现Header组件(其他布局组件同理)
Header组件负责顶部布局,核心是接收height属性并设置默认值:
<template>
<header
class="el-header"
:style="{ height }"
>
<slot />
</header>
</template>
<script lang="ts">
export default {
name: 'ElHeader'
}
</script>
<script setup lang="ts">
import { withDefaults } from 'vue'
// 定义Props并设置默认值
interface Props {
height?: string
}
withDefaults(defineProps<Props>(), {
height: "60px"
})
</script>
<style lang="scss">
@import '../styles/mixin';
@include b(header) {
padding: 0 20px; // 可抽离为全局变量
box-sizing: border-box;
flex-shrink: 0;
}
</style>
Footer、Aside、Main组件的实现逻辑与Header一致,仅样式和name不同,可参考Element3源码或文末的代码仓库。
四、组件注册:插件化封装,支持全局/按需引入
组件库需要对外提供友好的注册方式,我们用Vue的插件机制封装install方法,支持全局注册或按需引入。
在container目录下新建index.ts:
import { App } from 'vue'
import ElContainer from './Container.vue'
import ElHeader from './Header.vue'
import ElFooter from './Footer.vue'
import ElAside from './Aside.vue'
import ElMain from './Main.vue'
// 插件化封装
export default {
install(app: App) {
app.component(ElContainer.name, ElContainer)
app.component(ElHeader.name, ElHeader)
app.component(ElFooter.name, ElFooter)
app.component(ElAside.name, ElAside)
app.component(ElMain.name, ElMain)
}
}
在src/main.ts中全局注册:
import { createApp } from 'vue'
import App from './App.vue'
import ElContainer from './components/container'
const app = createApp(App)
// 全局注册布局组件
app.use(ElContainer)
app.mount('#app')
五、组件使用:快速实现页面布局
在App.vue中直接使用布局组件,即可快速实现常见页面布局:
<template>
<!– 垂直布局:Header + Main + Footer –>
<el-container>
<el-header>Header</el-header>
<el-main>Main</el-main>
<el-footer>Footer</el-footer>
</el-container>
<hr>
<!– 混合布局:Header + Aside + Main –>
<el-container>
<el-header>Header</el-header>
<el-container>
<el-aside width="200px">Aside</el-aside>
<el-main>Main</el-main>
</el-container>
</el-container>
</template>
<style>
body{
width: 1000px;
margin: 10px auto;
}
.el-header, .el-footer {
background-color: #1677ff;
color: #fff;
text-align: center;
line-height: 60px;
}
.el-aside {
background-color: #2e3a40;
color: #fff;
text-align: center;
line-height: 200px;
}
.el-main {
background-color: #f5f5f5;
color: #333;
text-align: center;
line-height: 200px;
}
</style>
最终效果如下(可参考Element3布局组件示例):
- 垂直布局:Header、Main、Footer自上而下排列
- 混合布局:Header在上,Aside和Main左右排列
六、常见问题与解决方案
1. Sass变量未定义(如$–header-padding)
问题:$–header-padding未定义导致编译报错。 解决方案:在src/styles下新建variables.scss,定义全局样式变量并引入:
// variables.scss
$–header-padding: 0 20px;
// 在Header.vue的style中引入
@import '../styles/variables';
2. TS类型报错(如VNode/Component未导出)
问题:import { VNode, Component } from 'vue'报错。 解决方案:确保Vue版本≥3.2,且tsconfig.json中开启moduleResolution: 'node'。
3. npx和npm的区别
- npm:安装包到项目/全局,但无法直接执行包内的命令;
- npx:临时安装并执行包的命令,无需全局安装,适合husky、vue-cli等工具的一次性执行。
4. Vue3语法选择(script/script setup/setup())
- <script setup>:推荐!Vue3.2+的语法糖,简洁高效,适合大部分组件开发;
- 普通<script>:用于设置组件name、全局注册等setup语法无法覆盖的场景;
- setup()函数:Vue3.2之前的写法,逐步被<script setup>替代。
七、总结与拓展
本文从环境搭建、规范约束到布局组件开发,完整实现了Vue3组件库的基础骨架。核心收获:
思考题
你负责的业务中,哪些组件适合抽离为通用组件库?比如:
- 业务通用的搜索框、分页组件;
- 统一的弹窗、加载动画;
- 适配业务的表格封装(如带筛选、排序的表格)。
后续我们还会继续讲解表单组件、表格组件、弹窗组件的实现,关注我,一起从0到1打造完整的Vue3组件库!


