前言
每个前端都一定积累了很多常用的组件,每次开新的项目都需要从旧的项目中拷贝一份通用组件,这时候你会发现cv大法好,但是每个组件都在不断的使用中慢慢演进和完善,新项目更新了组件的新属性,新方法,但是有一天旧项目又开始了新的迭代,原来别的项目新增的属性又要照搬过来,一个组件的更新就如此反复下去。。。
一旦有新人接手了这样的组件,他可能并不熟悉组件有哪些功能,也无法准确掌握哪个项目用的这个祖件是哪个版本;如果这样的基础组件有个十个八个的,那简直就是灾难。
相信深受其害的人一定不少,那就话不多说,组件库安排!
根据这一系列的文章,我会带你从头到脚实现一个代码库,从文档库的搭建,到使用npm发包,以及使用Lerna实现分包管理分包发布,让你的组件库支持按需引入,也支持分包安装。
选型
vuepress2.x: 以markdown形式的来书写组件库文档,并生成一个静态网站,支持vue3
element-plus: 第三方组件库,全面拥抱vue3,我们的宗旨是能复用就复用,绝不造第二遍轮子,组件库大多数都是基于element-plus的二次封装。
vuepress-plugin-demoblock-plus: demo代码块插件,用于实现像element-plus那样的demo示例文档,做到示例和代码块只写一次,做到所见即所得。
一、组件库搭建+页面布局
这部分就是傻瓜式安装,照着官方文档简单配置就可得到一套模版,链接戳此:快速开始
配置顶部导航+侧边导航
const { defaultTheme } = require('@vuepress/theme-default')
module.exports = {
lang: 'zh-CN',
title: '组件库',
description: '基于vue3 + element plus的UI组件库',
theme: defaultTheme({
// 导航栏配置
navbar: [
{ text: '组件', link: '/components/button.html' },
{
text: '更新日志',
link:'https://gitee.com/NewCoderMCL/vuepress-ui'
}
],
// 侧边栏数组
// 所有页面会使用相同的侧边栏
sidebar: {
// 侧边栏
"/": [
{
text: "介绍",
children: [
{ text: "项目简介", link: "/guide/intro" },
{ text: "快速上手", link: "/components/installation" },
],
},
{
text: "组件",
children: [
{ text: "Layout 布局", link: "/components/layout" },
{ text: "Table 表格", link: "/components/table.md" }
],
},
],
},
}),
}
使用vuepress-plugin-demoblock-plus插件实现demo-block文档渲染
同样是傻瓜式安装:戳此👇
怎么说呢,作者也在不断的更新维护,我在使用的时候插件还未全面支持最新版的vuepress,需要更换为新版require()的形式引入插件,不过作者也针对我的问题,给出了正解,在这里跪谢作者🙏。
如果你按着文档进行了安装和使用之后,仍然不生效,那么可以参考解决方案:解决vuepress2.0.0-beta.43版本使用不生效的问题,附上链接供大家参考。
二、注册封装组件以及引入第三方库
安装element-plus
yarn add element-plus -D
手动引入封装的组件,在docs/.vuepress/client.js文件配置如下,并引入第三方组件库
import { defineClientConfig } from '@vuepress/client'
// 全量引入element-plus
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
// 手动引入自己封装好的组件
import BaseTable from '../../packages/table/src/index.vue'
import '../../src/styles/index.css'
import './styles/index.less'
export default defineClientConfig({
enhance({ app }) {
// 注册element-plus
app.use(ElementPlus)
// 注册组件
app.component('BaseTable', BaseTable)
},
})
此时就可以在docs/components/ 文件夹下书写组件文档,以及示例,如下是table.md的内容:
:::demo
```vue
<template>
<base-table :tableData="tableData" :columns="columns"></base-table>
</template>
<script lang="ts" setup>
const columns = [
{
label: '编号',
type: 'index',
width: '80px'
},
{
label: '姓名',
value: 'name',
minWidth: '120px'
},
{
label: '年龄',
value: 'age',
minWidth: '120px'
}
]
const tableData = [
{
name: '张三',
age: '20',
}
]
</script>
```
:::
浏览器访问/components/table.html,效果如下:
查看代码示例:
⚠️注意:每次开发新的组件都需要在
docs/.vuepress/client.js中手动引入并注册组件,如果组件过多的话,这又是一些工作量,我们这种“懒蛋”当然要找轮子帮我们做这些工作啦,那就继续往下看吧。
自动注册组件
使用官方的插件register-components根据组件文件或目录自动注册 Vue 组件。
参考链接:v2.vuepress.vuejs.org/zh/referenc…
安装
yarn add -D @vuepress/plugin-register-components@next
.vuepress/config.js配置如下:
const { path } = require('@vuepress/utils')
const { registerComponentsPlugin } = require('@vuepress/plugin-register-components')
module.exports = {
...
plugins: [
registerComponentsPlugin({
componentsDir: path.resolve(__dirname, '../../packages'), // 需要自动引入的组件所在的文件夹
componentsPatterns:['**/*.vue'], // 组件格式为.vue结尾的文件
// 注册组件的名称,这里因人而异,我在注册组件时,都统一加了`base`前缀,
getComponentName:(filename) =>{
let compName = filename.split('/')[0].toLowerCase()
compName = compName.charAt(0).toUpperCase() + compName.slice(1)
return `base${compName}`
}
}),
]
}
按照此方式注册组件,会加一个base-的前缀,如组件目录为packages/table/src/index.vue,用自动注册baseTable组件,使用时可以用<base-table></base-table>
三、Q&A
1、vuepress不能热更新
将package.json的docs:dev由vuepress dev docs改为 vuepress dev docs --temp .temp
"scripts": {
"docs:dev": "vuepress dev docs --temp .temp",
"docs:build": "vuepress build docs"
},
2、其他demo代码块的使用,(这个有点难,没搞懂,后来放弃了,下面列了一些心路历程仅供参考)
参考:v2.vuepress.vuejs.org/zh/referenc…
1、安装插件@vuepress/plugin-container@next
yarn add -D @vuepress/plugin-container@next
在.vuepress/config.js添加如下配置:
const { containerPlugin } = require('@vuepress/plugin-container')
module.exports = {
plugins: [
containerPlugin({
// 配置项
type: 'demo',
validate(params) {
//函数在开始标记后验证尾部,成功时返回true
return params.trim().match(/^demo\s*(.*)$/);
},
render(tokens, idx) {
//渲染器函数
const m = tokens[idx].info.trim().match(/^demo\s*(.*)$/);
if (tokens[idx].nesting === 1) {
const description = m && m.length > 1 ? m[1] : '';
// opening tag
return `<demo-block>
<div slot="demo">组件demo</div>
<div slot="description">${description}</div>
<div slot="source">代码块</div>`;
} else {
// closing tag
return `</demo-block>`;
}
}
}),
.....
],
}
2、注册 demoBlock组件
新建组件:.vuepress/components/demoBlock.vue
<template>
<div class="block">
<div class="demo-content">
<!-- 插入组件 -->
<slot name="demo"></slot>
</div>
<div class="meta" ref="meta">
<div class="description">
<!-- 插入描述信息 -->
<slot name="description"></slot>
</div>
<div class="code-content">
<!-- 插入代码块 -->
<slot name="source"></slot>
</div>
</div>
</div>
</template>
注册组件:v2.vuepress.vuejs.org/zh/guide/mi…,文档给出两种方式注册vue组件,本文使用在 .vuepress/client.{js,ts} 中手动注册组件。
// .vuepress/client.js
import { defineClientConfig } from '@vuepress/client'
import demoBlock from './components/demoBlock.vue'
export default defineClientConfig({
enhance({ app }) {
// 注册组件
app.component('demoBlock', demoBlock)
},
})
此时在md文件中使用后效果如下:
3、从入门到放弃,走到这里,真的走不下去了,参考了各种开放的第三方组件库的demoBlock配置,发现太难了,不是报一堆错就是搞不明白,大家感兴趣的话可以试着实现实现,如果成功了希望能戳我下,跪谢🙏🙏🙏。
四、结语
后续内容:
- 使用
npm发包 - 使用
Lerna实现monorepo的单一代码块,实现组件库的分包管理分包发布
如果到目前为止,您还对我后续的文章感兴趣的话,那就持续关注吧~