在日常 Vue 项目开发中,我们难免需要写一些基础公共组件,在大型项目中,我们难免会遇到下面的痛点:
- 组件 API,对于 Vue 组件,有 props、event、slot 等接口,在团队内需要一定的沟通成本
- 对于 UI 组件,还需要提供预览,方便团队内快速选择合适的组件
如果使用 Markdown 撰写,虽然能写 API 文档,但是无法提供组件预览,并且手动写文档的成本也很大
好在有一个这样的库,可以提供自动化文档的生成,并提供组件预览,这个库叫做 Vue Styleguidist
安装
首先,Vue Styleguidist 只能适用于 Webpack 打包的项目,在此基础上,我们需要安装 vue-styleguidist
这个包
npm install vue-styleguidist --save-dev
然后在 package.json 配置下面两行命令,分别用于开发预览和部署打包
{
"scripts": {
"styleguide": "vue-styleguidist server",
"styleguide:build": "vue-styleguidist build"
}
}
如果是使用 @vue/cli 3 生成的项目,可以直接使用
vue-cli-plugin-styleguidist
这个插件进行更快捷的安装和配置
组件源代码
这里为了进行简单的演示,我们使用了 @vue/cli 3 生成项目,创建组件 src/components/AppButton/AppButton.vue
我们的组件源代码如下,下面的案例都会依照此源代码进行展开
<template>
<button
class="btn"
:type="htmlType"
:class="btnClass"
:disabled="disabled"
@click="handleClick"
>
<slot />
</button>
</template>
<script>
export default {
name: 'AppButton',
props: {
theme: {
type: String,
required: true,
},
outline: {
type: Boolean,
default: false,
},
size: {
type: String,
default: '',
},
block: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
htmlType: {
type: String,
default: 'button',
},
},
computed: {
btnClass() {
return {
[`btn-${this.theme}`]: !!this.theme && !this.outline,
[`btn-outline-${this.theme}`]: this.outline,
[`btn-${this.size}`]: !!this.size,
'btn-block': this.block,
};
},
},
methods: {
handleClick(e) {
this.$emit('click', e);
},
},
};
</script>
<style lang="scss">
@import '~bootstrap/scss/bootstrap';
</style>
Props
Props 是组件最基本的 API,用于为组件传递数据
实际上,在配置好 Vue Styleguidist 之后,如果有写 prop,就已经能生成一个这样的文档
我们可以看到,此时已经带出了 Props 的名称、参数类型、默认值、必填性等等
我们仅仅需要为 prop 写上相应的注释进行描述,像 JSDoc 一样,就能生成一份完整的 Props 说明
export default {
props: {
/**
* 按钮主题,有效值:
*/
theme: {
type: String,
required: true,
},
/**
* 启用outline样式
*/
outline: {
type: Boolean,
default: false,
},
/**
* 按钮大小,有效值:lg sm
*/
size: {
type: String,
default: '',
},
/**
* 启用块状按钮
*/
block: {
type: Boolean,
default: false,
},
/**
* 禁用状态
*/
disabled: {
type: Boolean,
default: false,
},
/**
* 按钮类型,有效值:button submit reset
*/
htmlType: {
type: String,
default: 'button',
},
},
};
最终会得到一份完整的 Props 说明
Events
除了 Props,Event 事件也是 Vue 的一个重要的 API 之一,可以通过 v-on
为组件绑定事件
Vue 的事件使用 vm.$('event', ...params)
的方法进行定义,我们只需要在这个方法之前,加上必要的注释就可以了
- 如果事件名不是字符串,可以使用
@event
进行标注 - 事件的参数使用
@type
进行标注
export default {
methods: {
handleClick(e) {
/**
* 单击事件
* @type {Event}
*/
this.$emit('click', e);
},
},
};
Slots
Slot 插槽是 Vue 的自定义元素之一,Slot 向一个组件传递内容,也是封装公共组件常见的 API 之一
与 Props 和 Events 不同的是,Slots 通常是定义在 <template>
部分,不能使用 JS 注释进行标注,需要使用 HTML 注释,并且在注释里使用 @slot
进行标注
<button
class="btn"
:type="htmlType"
:class="btnClass"
:disabled="disabled"
@click="handleClick"
>
<!-- @slot 按钮的内容 -->
<slot />
</button>
如果使用的是具名 Slot(具名插槽),则会自动生成插槽名称
<button
class="btn"
:type="htmlType"
:class="btnClass"
:disabled="disabled"
@click="handleClick"
>
<!-- @slot 按钮的图标 -->
<slot name="icon" />
<!-- @slot 按钮的内容 -->
<slot />
</button>
Methods
看到这里可能各位会有个疑问,Methods 和 Events 有什么区别?
区别主要有以下两个:
- 定义方式不同:Methods 只要在
methods
里定义函数即可,Events 则需要使用vm.$('event', ...params)
进行定义 - 调用方式不同:Methods 使用
vm.$refs.ref.method()
这样的方式进行调用,Events 使用v-on
指令或者vm.$on('event')
进行监听
实际上,使用 Methods 方法封装组件 API 的情况是比较少的,但是依然不能排除这种情况
对于 Methods 方法,我们只需要像使用 JSDoc 一样为函数进行注释就可以了,最后再附上 @public
进行标识
export default {
methods: {
/**
* 单击事件
* @param {Event} e
* @public
*/
click(e) {
// some code
},
},
};
编写样例
通过上面的例子,我们将至少得到一个这样的文档
这个文档把该有的 API 都暴露出来了,但是它并不是完美无缺的:
- 直接对比 Markdown 文档,并没有明显的优势
- 缺乏组件 UI 样例
在文章的开头,我们说过,UI 组件需要为团队提供样式预览,并且需要自动生成
很遗憾的是,Vue Styleguidist 并不能直接生成预览样式,这个需要手写样式代码
在 Vue Styleguidist,有两种编写组件样例的方式
README方式
在组件的同个目录下,新建一个文件 README.md
,比如 src/components/AppButton/README.md
然后直接调用组件代码
这样我们就能快速简洁的生成一个预览+示例代码了
我们也可以为组件传入 Props,预览组件的表现
<docs>组件方式
可以直接在组件下方增加一个组件 <docs></docs>
,并在里面直接使用 Markdown 编写样例,这种方式适用于项目结构比较简单的项目,但是我认为会使组件的代码变得很冗长,在此不再赘述
配置
Vue Styleguidist 支持自定义配置,只需要在项目根目录下,创建 styleguide.config.js
,就可以参照官方文档进行配置
// styleguide.config.js
module.exports = {
title: 'Default Style Guide', // 文档的标题
components: 'src/components/**/*.vue', // 组件的目录
defaultExample: false, // 是否使用默认样例
usageMode: 'expand', // 是否展开用法
exampleMode: 'expand', // 是否展开示例代码
styleguideDir: 'styleguide', // 打包的目录
codeSplit: true, // 打包时是否进行分片
skipComponentsWithoutExample: true, // 是否跳过没有样例的组件
};
注意事项和总结
注意事项
- JSDoc 的标签仍然有效
- TypeScript、Flow 和 Class 组件同样可以使用,只是使用方法稍有不同
- JSX 也可以使用
总结
通过 Vue Styleguidist,我们将至少得到下面两项好处:
- 完整的组件 API 和用法
- 直观的组件预览
另外我认为还能得到以下几项好处:
- 完善的注释
- 较小的 UI 调试成本
- 减少团队内部沟通成本
Vue Styleguidist 实际上还拥有多种配置和用法,各位感兴趣可以去官网看看文档
题外话:实际上 Vue Styleguidist 来源于 React Styleguidist(也依赖于这个项目),使用方法大同小异,不同于 Vue 组件的是,React 组件的 API 只有 Props 一项