接上回我们搭建完组件库项目,现在还剩下组件文档,因为从 0 开始搭建文档太费时间,我推荐大家使用vitepress进行快速搭建,它可以将你的 Markdown 转为文档页面,所以我们只需要写 md 文件既可快速实现文档开发。它自带了很多样式,如果你不喜欢,可以自定义主题,自定义主题的东西比较多,你也可以查询官网相关文档进行学习。
文档目录结构创建
上节我们在根目录下创建了一个 docs
的文件夹,我们接下来需要在这个文件夹下创建我们的组件库文档的项目。
我们在 docs
目录下打开终端,输入以下命令:
npx vitepress init
一直往下进行,你就会得到这样的文件结构:
我们在组件库根目录下安装一下 vitepress
依赖
pnpm i vitepress -D -w
然后我们需要在根目录package.json
中添加一下 vitepress
项目运行命令:
{
"name": "test-ui",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "vite examples",
"test": "echo \"Error: no test specified\" && exit 1",
"docs:dev": "vitepress dev docs", // 文档dev环境运行
"docs:build": "vitepress build docs", // 文档打包
"docs:preview": "vitepress preview docs" // 文档预览
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@test-ui/components": "workspace:^",
"@test-ui/examples": "workspace:^"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.1.2",
"vite": "^5.3.5",
"vitepress": "^1.3.2"
}
}
执行运行命令,运行看一下是否能正常启动
npm run docs:dev
这就表明已经成功运行了,说一下重点的文件
├─ docs // 站点项目根目录
│ ├─ .vitepress // VitePress 配置文件、开发服务器缓存、构建输出和可选主题自定义代码的位置
│ │ └─ config.js // 配置文件
│ ├─ api-examples.md
│ ├─ markdown-examples.md
│ └─ index.md // 默认首页
└─ package.json
接下来我们需要导入我们组件进行注册。
组件的注册以及使用
要在组件库中显示出组件,我们必须得将我们开发的组件库安装到这个 vitepress 项目中,那我们怎么去安装呢?我们可以通过自定义主题来对当前的项目进行安装任何包,包括我们的组件库。
根据官网所说,我们需要在.vitepress
文件夹下创建一个 theme
文件夹,在该文件夹下创建一个 index.js
或者 index.ts
文件作为主题入口文件。
.
├─ docs # 项目根目录
│ ├─ .vitepress
│ │ ├─ theme
│ │ │ └─ index.js # 主题入口
│ │ └─ config.js # 配置文件
│ └─ index.md
└─ package.json
写入以下内容:
import DefaultTheme from "vitepress/theme";
import TestUI from "@test-ui/components";
export default {
...DefaultTheme,
enhanceApp: async ({ app, router, siteData }) => {
app.use(TestUI);
},
};
enhanceApp
对应的函数入参中 app
代表当前 vue 实例,意味着我们可以使用它进行注册组件、定义指令等等。
我们清空一下默认带的markdown-examples.md
,直接写入我们的组件,看看是否成功渲染。
好耶 🎉 看来是已经成功渲染了,由于 vitepress 有默认的样式,我们的 button 样式已经被重置了,我们修改一下组件样式来看看
目前我用的是 less 预编译器,这个可以根据个人喜好来选择你的组件库 css 预编译器 根目录下安装 pnpm i less less-loader -D -w 在
theme-chalk
文件夹下创建index.less
文件作为组件库样式入口文件,后续我们编写组件的时候再具体划分结构
我们在 theme-chalk
下 index.less
文件中修改一下我们的 button 组件样式,并在文档注册我们组件的地方导入我们组件的样式文件。
.t-button {
display: inline-block;
border: 1px solid #ddd;
padding: 4px 8px;
border-radius: 4px;
font-size: 14px;
background-color: #409eff;
color: #fff;
}
import DefaultTheme from "vitepress/theme";
import TestUI from "@test-ui/components";
import "@test-ui/theme-chalk/index.less"; // 引入样式文件
export default {
...DefaultTheme,
enhanceApp: async ({ app, router, siteData }) => {
app.use(TestUI);
},
};
结果如下:
组件源码预览
在做这个源码预览的时候我也找过相关别人做的一些插件,暂时没有找到什么特别好用的,所以打算自己写,那就带大家来写一个组件源码预览的组件吧。
首先我们先去想怎么去实现,组件预览一般上面是组件的展示,下面有个按钮可以展开查看源码,也就是上面的组件预览我可以作为一个插槽,直接传入我要展示的组件,下面源码就是我这个组件实现的代码,是一整个代码字符串,但是每个组件演示都需要我写这么多字符串给传入进去,是不是很麻烦,既然显示的代码就是我传入插槽的组件,那我可不可以直接将某一个示例的代码写为一个 vue 文件,这个文件既可以当做一个组件传入预览组件的插槽,又可以直接读取这个示例的 vue 文件中的字符串进行展示,这样就完美解决了我的示例代码需要重新写一次的问题。
好了,现在问题还有两个:
- 怎么读取 vue 文件中的字符串?
- 怎么更好的排版以及高亮我们示例代码?
我直接公布答案:
- vite 中资源可以使用
?raw
后缀声明作为字符串引入,vite 官网文档:将资源引入为字符串 - highlight.js 互联网上最受欢迎的 JavaScript 语法高亮器,支持 192 种语言和 498 个主题。
好了,我们开始动手来开发一个这个预览组件吧!
我们在文档的项目中 theme
文件夹下创建一个 preview
文件夹然后在里面创建一个 vue 文件,这个就是我们要准备开发的组件。我们随便给里面写点东西,我们上面说了 theme
文件夹下的 index.js 文件中 enhanceApp
方法可以通过入参中的 app
相当于当前组件库文档的 vue 实例,那么我们就可以在这个上面进行注册我们的组件.
preview 组件:
<template>
<div><slot /></div>
</template>
<script setup></script>
<style scoped></style>
import DefaultTheme from "vitepress/theme";
import TestUI from "@test-ui/components";
import "@test-ui/theme-chalk/index.less"; // 引入样式文件
import Preview from "./preview/index.vue";
export default {
...DefaultTheme,
enhanceApp: async ({ app, router, siteData }) => {
app.use(TestUI);
app.component("preview", Preview); // 注册预览功能的组件
},
};
我们在markdown-examples.md
中使用一下我们注册的组件,发现可以直接使用,那说明我们成功注册了,接下来就要写逻辑了。
因为我们后续有很多组件的文档,我们需要规划一下我们组件文档的结构,我们创建如下文档结构,便于我们清晰主观的书写组件文档,demo.vue 我们会写组件的使用代码,index.md 就是我们一个组件所有的使用说明。
index.md
# Button 按钮
<preview>
<t-button>button</t-button>
</preview>
我们修改一下 config.mts
配置文件
import { defineConfig } from "vitepress";
export default defineConfig({
title: "My Awesome Project",
description: "A VitePress Site",
themeConfig: {
nav: [
{ text: "首页", link: "/" },
{ text: "组件", link: "/components/button/" },
],
sidebar: {
"/components/": [
{
text: "基本",
items: [{ text: "Button 按钮", link: "/components/button/" }],
},
],
},
socialLinks: [{ icon: "github", link: "https://github.com/vuejs/vitepress" }],
},
});
修改完成之后我们是这个样子
我们安装一下 highlight.js
pnpm i highlight.js @highlightjs/vue-plugin -w
然后使用
import DefaultTheme from "vitepress/theme";
import TestUI from "@test-ui/components";
import "@test-ui/theme-chalk/index.less"; // 引入样式文件
import Preview from "./preview/index.vue";
import "highlight.js/styles/base16/summerfruit-light.css"; // 主题
import hljsVuePlugin from "@highlightjs/vue-plugin";
export default {
...DefaultTheme,
enhanceApp: async ({ app, router, siteData }) => {
app.use(TestUI);
app.component("preview", Preview); // 注册预览功能的组件
app.use(hljsVuePlugin);
},
};
preview
组件的封装如下代码,相信大家都能看懂,就不做解释了
<template>
<div class="demo_preview">
<div class="preview_box">
<slot />
</div>
<div class="code_box">
<div class="code" :class="{ show_code: showCode }">
<div class="code__reference">
<div class="code_content">
<highlightjs autodetect :code="sourceCode" />
</div>
</div>
</div>
<div class="operate_btn" @click="handleClick">{{ showCode ? "隐藏" : "显示" }}代码</div>
</div>
</div>
</template>
<script setup>
import { onMounted, reactive, toRefs } from "vue";
import "highlight.js";
const props = defineProps({
compName: {
type: String,
default: "",
},
demoName: {
type: String,
default: "",
},
});
onMounted(() => {
componentCode();
});
const state = reactive({
sourceCode: "",
showCode: false,
demoHTML: "",
});
const { sourceCode, showCode, demoHTML } = toRefs(state);
const componentCode = async () => {
const data = await import(`../../../components/${props.compName}/${props.demoName}.vue?raw`);
state.sourceCode = data.default;
};
const handleClick = () => {
state.showCode = !state.showCode;
};
</script>
<style scoped>
.demo_preview {
margin: 20px 0;
border: 1px solid #efefef;
border-radius: 6px;
overflow: hidden;
}
.preview_box {
padding: 20px;
}
.operate_btn {
position: relative;
height: 46px;
line-height: 46px;
color: #666;
text-align: center;
background: #f7f7f7;
cursor: pointer;
z-index: 100;
}
.operate_btn:hover {
background: #f2f2f2;
}
.code {
border-top: 1px solid #efefef;
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows 0.3s ease;
}
.code .code__reference {
overflow: hidden;
}
.show_code {
grid-template-rows: 1fr;
}
</style>
我们在 demo1.vue
的文件中写几个示例
<template>
<t-button>aaa</t-button>
<t-button>bbb</t-button>
</template>
我们重新修改一下 button 的 md 文档
<script setup>
import demo1 from './demo1.vue'
</script>
# Button 按钮
<preview comp-name="button" demo-name="demo1">
<demo1/>
</preview>
我们来看一下效果:
到此,我们的组件库文档大体已经完成了,剩下的就是大家自己根据喜好去配置你的首页、菜单之类的,下节我们将开始封装组件,还希望大家能够持续关注,多多点赞 🤝