You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

15 KiB

20组件库如何设计你自己的通用组件库

你好我是大圣。上一讲TypeScript加餐学完你是不是想赶紧巩固一下TypeScript在Vue中的使用呢那么从今天开始我们就重点攻克Vue中组件库的实现难点我会用7讲的篇幅带你进入组件库的世界。

学习路径大致是这样的首先我会给你拆解一下Element3组件库的代码其次带你剖析组件库中一些经典的组件比如表单、表格、弹窗等组件的实现细节整体使用Vite+TypeScript+Sass的技术栈来实现。而业务中繁多的页面也是由一个个组件拼接而成的所以我们可以先学习一下不同类型的组件是如何去设计的借此举一反三。

环境搭建

下面我们直奔主题,开始搭建环境。这个章节的代码我已经推送到了Github由于组件库是模仿Element实现的所以我为其取名为ailemente。

接下来我们就一步步实现这个组件库吧。首先和开发项目一样我们要在命令行里使用下面的命令创建Vite项目模板选择vue-ts这样我们就拥有了一个Vite+TypeScript的开发环境。

npm init vite@latest

图片

关于ESLint和Sass的相关配置全家桶实战篇我们已经详细配置了这里只补充一下husky的内容。husky这个库可以很方便地帮助我们设置Git的钩子函数可以允许我们在代码提交之前进行代码质量的监测。

下面的代码中我们首先安装和初始化了husky然后我们使用 npx husky add命令新增了commit-msg钩子husky会在我们执行git commit提交代码的时候执行 node scripts/verifyCommit命令来校验commit信息格式。

npm install -D husky # 安装husky
npx husky install    # 初始化husky
# 新增commit msg钩子
npx husky add .husky/commit-msg "node scripts/verifyCommit.js" 

然后我们来到项目目录下的verifyCommit文件。在下面的代码中我们先去 .git/COMMIT_EDITMSG文件中读取了commit提交的信息然后使用了正则去校验提交信息的格式。如果commit的信息不符合要求会直接报错并且终止代码的提交。



const msg = require('fs')
  .readFileSync('.git/COMMIT_EDITMSG', 'utf-8')
  .trim()
  
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: xxbug
      feat(test): add new 
      具体校验逻辑看 scripts/verifyCommit.js
    `)
    process.exit(1)
  }

}else{
  console.log('git commit信息校验通过')
}


这样就确保在GitHub中的提交日志都符合type(scope): message 的格式。你可以看下Vue 3的代码提交记录每个提交涉及的模块类型和信息都清晰可见能够很好地帮助我们管理版本日志校验正则的逻辑。如下图feat代表新功能docs代表文档perf代表性能。下面的提交日志就能告诉我们这次提交的是组件相关的新功能代码中新增了Button.vue。

feat(component): add Button.vue

图片

commit-msg是代码执行提交的时候执行的我们还可以使用代码执行之前的钩子pre-commit去执行ESLint代码格式。这样我们在执行git commit的同时就会首先进行ESLint校验然后执行commit的log信息格式检查全部通过后代码才能提交至Git这也是现在业界通用的解决方案学完你就快去优化一下手里的项目吧

npx husky add .husky/pre-commit "npm run lint"

布局组件

好,现在环境我们就搭建好了,接着看看怎么布局组件。

我们可以参考Element3组件列表页面,这里的组件分成了基础组件、表单组件、数据组件、通知组件、导航组件和其他组件几个类型,这些类型基本覆盖了组件库的适用场景,项目中的业务组件也是由这些类型组件拼接而来的。

我们还可以参考项目模块的规范搭建组件库的模板包括Sass、ESLint等组件库会在这些规范之上加入单元测试来进一步确保代码的可维护性。

接下来我们逐一讲解下各个组件的负责范围。

首先我们需要设计基础的组件也就是整个项目中都会用到的组件规范包括布局、色彩字体、图标等等。这些组件基本没有JavaScript的参与实现起来也很简单负责的就是项目整体的布局和色彩设计。

而表单组件则负责用户的输入数据管理,包括我们常见的输入框、滑块、评分等等,总结来说,需要用户输入的地方就是表单组件的应用场景,其中对用户的输入校验是比较重要的功能点。

数据组件负责显示后台的数据,最重要的就是表格和树形组件。

通知组件负责通知用户操作的状态,包括警告和弹窗,如何用函数动态渲染组件是警告组件的重要功能点。

接下来我们就动手设计一个基础的布局组件,这个组件相对是比较简单的。你可以访问Element3布局容器页面这里一共有container、header、footer、aside、main五个组件这个组合可以很方便地实现常见的页面布局。

  • el-container组件负责外层容器当子元素中包含  或  时全部子元素会垂直上下排列否则会水平左右排列。
  • el-header、el-aside、el-main、el-footer 组件分别负责顶部和侧边栏页面主体和底部容器组件。这个功能比较简单只是渲染页面的布局。我们可以在src/components目录下新建文件夹container新建Container.vue布局组件没有交互逻辑只需要通过flex布局就可以实现。

这几个组件只是提供了不同的class这里就涉及到CSS的设计内容。在Element3中所有的样式前缀都是el开头每次都重复书写维护太困难所以我们设计之初就需要涉及Sass的Mixin来提高书写CSS的代码效率。

接着我们在src/styles下面新建mixin.scss。在下面的代码中我们定义了namespace变量为el使用Mixin注册一个可以重复使用的模块b可以通过传进来的block生成新的变量$B并且变量会渲染在class上并且注册了when可以新增class选择器实现多个class的样式。

// bem

$namespace: 'el';
@mixin b($block) {
  $B: $namespace + '-' + $block !global;
  .#{$B} {
    @content;
  }
}

// 添加ben后缀啥的
@mixin when($state) {
  @at-root {
    &.#{$state-prefix + $state} {
      @content;
    }
  }
}

代码看着有些抽象,不要急,我们再在 container.vue中写上下面的代码。使用@import导入mixin.scss后就可以用include语法去使用Mixin注册的代码块。

<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>

在上面的代码中我们使用b(container)生成.el-container样式类在内部使用when(vertical)生成.el-container.is-vertical样式类去修改flex的布局方向。

.el-container {
  display: flex;
  flex-direction: row;
  flex: 1;
  flex-basis: auto;
  box-sizing: border-box;
  min-width: 0;
}
.el-container.is-vertical {
  flex-direction: column;
}

container组件如果内部没有header或者footer组件就是横向布局否则就是垂直布局。根据上面的CSS代码我们可以知道只需要新增is-vertical这个class就可以实现垂直布局。

我们在Container.vue中写下下面的代码template中使用el-container容器包裹通过:class来实现样式控制即可。然后你肯定会疑惑为什么会有两个script标签

因为开发组件库的时候我们要确保每个组件都有自己的名字script setup中没法返回组件的名字所以我们需要一个单独的标签使用options的语法设置组件的name属性。

然后在