各位好,我是你们今天的组件规范讲师,代号“砖家”,负责把大家从“组件搬运工”升级为“组件架构师”(至少听完这次讲座后,感觉自己像)。今天咱们聊聊在一个多团队协作的 Vue 项目中,如何设计一套通用的组件库规范,并且用 Storybook 来管理组件文档。
咱们的目标是:
- 清晰的组件规范: 让每个团队都能按照统一的标准开发、使用组件,避免出现“这个组件是 A 团队写的,只有 A 团队的人才敢动”的尴尬局面。
- 完善的组件文档: 告别“祖传代码,注释全无”的噩梦,让新同学也能快速上手、轻松维护。
- 高效的协作流程: 减少沟通成本,提高开发效率,让大家有更多的时间摸鱼…哦不,是提升自我。
一、组件库规范:立规矩,才能成方圆
规范是组件库的灵魂,没有灵魂的组件库,就像没有馅儿的包子,空虚寂寞冷。我们的规范应该包含以下几个方面:
1.1 组件命名规范
- 组件命名方式: 统一使用 PascalCase(大驼峰命名法),比如
MyAwesomeButton
、UserProfileCard
。 这样一眼就能看出是个组件。 - 组件文件命名: 组件文件也采用 PascalCase,比如
MyAwesomeButton.vue
。 -
组件目录结构: 按照功能或模块进行组织,比如:
src/components/ ├── Button/ │ ├── MyAwesomeButton.vue │ └── MyAwesomeButton.stories.js ├── Card/ │ ├── UserProfileCard.vue │ └── UserProfileCard.stories.js └── ...
这样做的好处是,找组件的时候就像逛超市,货架分类清晰,妈妈再也不用担心我找不到东西了。
1.2 Props 规范
-
Props 类型: 明确指定 Props 的类型,比如
String
、Number
、Boolean
、Array
、Object
、Function
、Symbol
。 避免出现类型错误,导致组件行为异常。<template> <button :class="buttonClass" @click="handleClick"> {{ label }} </button> </template> <script> export default { props: { label: { type: String, required: true, default: 'Click me', description: '按钮显示的文本' }, type: { type: String, default: 'primary', validator: (value) => ['primary', 'secondary', 'danger'].includes(value), description: '按钮类型' }, disabled: { type: Boolean, default: false, description: '是否禁用按钮' } }, computed: { buttonClass() { return `button button--${this.type} ${this.disabled ? 'button--disabled' : ''}`; } }, methods: { handleClick() { this.$emit('click'); } } } </script>
-
Props 默认值: 为 Props 设置合理的默认值,避免组件在没有接收到 Props 时出现错误。
-
Props 校验: 使用
validator
函数对 Props 的值进行校验,确保 Props 的值符合预期。 -
Props 描述: 使用
description
对 Props 进行描述,方便其他开发者理解 Props 的作用。
1.3 Events 规范
-
事件命名: 使用 kebab-case(短横线命名法),比如
my-awesome-event
、user-profile-updated
。 -
事件参数: 明确事件参数的类型和含义,方便其他开发者使用。
<template> <input type="text" @input="handleInput" /> </template> <script> export default { methods: { handleInput(event) { const value = event.target.value; this.$emit('input-change', value); // 触发 input-change 事件,传递输入框的值 } } } </script>
-
事件描述: 使用注释对事件进行描述,方便其他开发者理解事件的作用。
1.4 Slots 规范
-
具名 Slots: 使用具名 Slots 明确指定 Slots 的作用域,提高组件的灵活性。
<!-- MyComponent.vue --> <template> <div> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div> </template>
<!-- 使用 MyComponent --> <template> <MyComponent> <template v-slot:header> <h1>This is the header</h1> </template> <p>This is the main content</p> <template v-slot:footer> <p>This is the footer</p> </template> </MyComponent> </template>
-
Slots 默认内容: 为 Slots 设置默认内容,避免组件在没有接收到 Slots 时显示空白。
-
Slots 描述: 使用注释对 Slots 进行描述,方便其他开发者理解 Slots 的作用。
1.5 Style 规范
-
CSS 命名: 统一使用 BEM 命名规范(Block Element Modifier),提高 CSS 的可维护性和可读性。
/* Block */ .button { /* ... */ } /* Element */ .button__label { /* ... */ } /* Modifier */ .button--primary { /* ... */ }
-
CSS 样式: 推荐使用 CSS Modules 或 scoped CSS,避免样式冲突。
-
样式文件: 将组件的样式放在单独的 CSS 文件中,方便维护和管理。
1.6 代码风格规范
- ESLint: 使用 ESLint 进行代码检查,确保代码风格一致。
- Prettier: 使用 Prettier 进行代码格式化,自动调整代码风格。
- Commit 规范: 使用 Conventional Commits 规范,方便生成 Changelog。
1.7 其他规范
- 组件文档: 每个组件都必须有完善的文档,包括 Props、Events、Slots 的描述、示例代码、使用场景等。
- 单元测试: 为核心组件编写单元测试,确保组件的质量。
- 版本控制: 使用 Git 进行版本控制,方便协作和回滚。
总结一下,我们可以用一个表格来概括组件规范:
规范类别 | 具体内容 | 备注 |
---|---|---|
组件命名 | PascalCase(大驼峰命名法) | 易于识别组件 |
组件文件 | PascalCase.vue | 与组件命名保持一致 |
组件目录 | 按照功能或模块组织 | 方便查找和管理 |
Props | 明确类型、设置默认值、进行校验、添加描述 | 确保 Props 的正确性和易用性 |
Events | kebab-case(短横线命名法)、明确参数类型和含义、添加描述 | 方便使用和理解 |
Slots | 具名 Slots、设置默认内容、添加描述 | 提高组件的灵活性和易用性 |
Style | BEM 命名规范、CSS Modules 或 scoped CSS、单独的 CSS 文件 | 提高 CSS 的可维护性和可读性,避免样式冲突 |
代码风格 | ESLint、Prettier、Conventional Commits | 确保代码风格一致,方便生成 Changelog |
组件文档 | 完善的 Props、Events、Slots 描述、示例代码、使用场景 | 方便其他开发者使用 |
单元测试 | 为核心组件编写单元测试 | 确保组件的质量 |
版本控制 | Git | 方便协作和回滚 |
二、Storybook:组件的百宝箱,文档的避风港
有了规范,接下来就要用 Storybook 来管理我们的组件文档了。Storybook 是一个强大的组件开发和文档工具,它可以让我们:
- 独立开发组件: 在隔离的环境中开发组件,不受项目其他部分的影响。
- 可视化组件: 通过 Storybook 的界面,可以直观地看到组件的效果。
- 编写组件文档: 使用 Markdown 或 MDX 编写组件文档,方便其他开发者理解和使用。
- 测试组件: 使用 Storybook 的插件,可以对组件进行单元测试和集成测试。
2.1 安装 Storybook
首先,我们需要在项目中安装 Storybook:
npx sb init
这个命令会自动检测你的项目类型,并安装相应的依赖。如果你的项目是 Vue 项目,它会安装 @storybook/vue3
。
2.2 创建 Story
Story 是 Storybook 中的一个概念,它描述了组件在不同状态下的表现。我们可以为每个组件创建一个或多个 Story。
在组件目录中创建一个 *.stories.js
文件,比如 src/components/Button/MyAwesomeButton.stories.js
:
import MyAwesomeButton from './MyAwesomeButton.vue';
export default {
title: 'Button/MyAwesomeButton', // Storybook 中显示的组件名称
component: MyAwesomeButton, // 组件本身
argTypes: {
label: { control: 'text', description: '按钮显示的文本' },
type: {
control: { type: 'select', options: ['primary', 'secondary', 'danger'] },
description: '按钮类型'
},
disabled: { control: 'boolean', description: '是否禁用按钮' },
onClick: { action: 'clicked', description: '点击事件' } // 模拟事件
},
};
const Template = (args) => ({
components: { MyAwesomeButton },
setup() {
return { args };
},
template: '<MyAwesomeButton v-bind="args" @click="args.onClick" />',
});
export const Primary = Template.bind({});
Primary.args = {
label: 'Primary Button',
type: 'primary',
};
export const Secondary = Template.bind({});
Secondary.args = {
label: 'Secondary Button',
type: 'secondary',
};
export const Danger = Template.bind({});
Danger.args = {
label: 'Danger Button',
type: 'danger',
};
export const Disabled = Template.bind({});
Disabled.args = {
label: 'Disabled Button',
disabled: true,
};
这个 Story 文件定义了:
title
: 组件在 Storybook 中的名称。component
: 组件本身。argTypes
: 组件的 Props 和 Events 的描述,以及控制方式。control: 'text'
:使用文本框控制 Props 的值。control: { type: 'select', options: [...] }
:使用下拉框控制 Props 的值。control: 'boolean'
:使用开关控制 Props 的值。action: 'clicked'
:模拟事件,在 Storybook 中点击按钮时会显示 "clicked" 事件被触发。
Template
: 组件的模板,用于渲染组件。Primary
、Secondary
、Danger
、Disabled
: 组件的不同状态,每个状态都有不同的 Props 值。
2.3 运行 Storybook
安装完成后,你可以在 package.json
文件中找到 Storybook 的启动命令:
{
"scripts": {
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build"
}
}
运行 npm run storybook
或 yarn storybook
就可以启动 Storybook 了。
打开浏览器,访问 http://localhost:6006
,你就可以看到 Storybook 的界面了。
2.4 使用 MDX 编写文档
除了使用 JavaScript 编写 Story 之外,我们还可以使用 MDX(Markdown + JSX)编写更丰富的文档。
创建一个 *.stories.mdx
文件,比如 src/components/Button/MyAwesomeButton.stories.mdx
:
import { Meta, Story, Canvas, ArgsTable } from '@storybook/addon-docs';
import MyAwesomeButton from './MyAwesomeButton.vue';
<Meta title="Button/MyAwesomeButton" component={MyAwesomeButton} />
# MyAwesomeButton
这是一个非常棒的按钮组件。
## Props
<ArgsTable of={MyAwesomeButton} />
## Examples
<Canvas>
<Story name="Primary">
<MyAwesomeButton label="Primary Button" type="primary" />
</Story>
<Story name="Secondary">
<MyAwesomeButton label="Secondary Button" type="secondary" />
</Story>
<Story name="Danger">
<MyAwesomeButton label="Danger Button" type="danger" />
</Story>
<Story name="Disabled">
<MyAwesomeButton label="Disabled Button" disabled />
</Story>
</Canvas>
这个 MDX 文件使用了 Storybook 的 addon-docs
插件,可以让我们在 Markdown 中嵌入 JSX 代码,从而编写更丰富的文档。
<Meta>
: 定义 Storybook 中显示的组件名称和组件本身。# MyAwesomeButton
: Markdown 标题。<ArgsTable>
: 显示组件的 Props 表格。<Canvas>
: 创建一个画布,用于显示组件的示例。<Story>
: 定义组件的不同状态。
2.5 Storybook 常用插件
Storybook 有很多有用的插件,可以帮助我们更好地开发和管理组件文档。
@storybook/addon-knobs
: 允许我们在 Storybook 中动态修改 Props 的值,方便调试组件。@storybook/addon-actions
: 模拟事件,在 Storybook 中点击按钮时会显示事件被触发。@storybook/addon-viewport
: 模拟不同的设备屏幕尺寸,方便测试组件的响应式布局。@storybook/addon-backgrounds
: 切换不同的背景颜色,方便测试组件的颜色对比度。@storybook/addon-a11y
: 检查组件的可访问性问题。
2.6 集成到 CI/CD
我们可以将 Storybook 集成到 CI/CD 流程中,每次代码提交时自动构建 Storybook,并将其部署到静态服务器上。这样,团队成员就可以随时访问最新的组件文档。
总结一下,我们可以用一个表格来概括 Storybook 的使用:
功能 | 描述 | 示例 |
---|---|---|
安装 | npx sb init |
安装 Storybook |
创建 Story | 创建 *.stories.js 或 *.stories.mdx 文件 |
import MyAwesomeButton from './MyAwesomeButton.vue'; export default { title: 'Button/MyAwesomeButton', component: MyAwesomeButton, argTypes: { label: { control: 'text' } } }; const Template = (args) => ({ components: { MyAwesomeButton }, setup() { return { args }; }, template: '<MyAwesomeButton v-bind="args" />', }); export const Primary = Template.bind({}); Primary.args = { label: 'Primary Button' }; |
运行 | npm run storybook 或 yarn storybook |
启动 Storybook |
MDX 文档 | 使用 Markdown + JSX 编写文档 | import { Meta, Story, Canvas, ArgsTable } from '@storybook/addon-docs'; import MyAwesomeButton from './MyAwesomeButton.vue'; <Meta title="Button/MyAwesomeButton" component={MyAwesomeButton} /> # MyAwesomeButton <ArgsTable of={MyAwesomeButton} /> <Canvas> <Story name="Primary"> <MyAwesomeButton label="Primary Button" /> </Story> </Canvas> |
常用插件 | @storybook/addon-knobs 、@storybook/addon-actions 、@storybook/addon-viewport 、@storybook/addon-backgrounds 、@storybook/addon-a11y |
动态修改 Props 的值、模拟事件、模拟设备屏幕尺寸、切换背景颜色、检查可访问性问题 |
集成 CI/CD | 自动构建和部署 Storybook | 方便团队成员随时访问最新的组件文档 |
三、多团队协作流程:步调一致,才能走得更远
有了规范和文档,接下来就要建立一套高效的多团队协作流程。
3.1 组件评审
每个团队开发的组件都需要经过评审,确保组件符合规范、质量可靠、易于使用。
- 评审人员: 至少包括一个来自其他团队的成员,以及一个 UI/UX 设计师。
- 评审内容:
- 组件是否符合规范?
- 组件的 Props、Events、Slots 是否清晰易懂?
- 组件的文档是否完善?
- 组件的样式是否符合设计规范?
- 组件的性能是否良好?
- 组件的可访问性是否良好?
- 评审流程:
- 开发者提交组件代码和 Storybook 文档。
- 评审人员 review 代码和文档,提出修改意见。
- 开发者修改代码和文档,直到评审通过。
3.2 版本管理
组件库的版本管理非常重要,可以避免不同团队使用不同版本的组件,导致兼容性问题。
- 版本号: 统一使用 Semantic Versioning(语义化版本)规范,比如
1.2.3
。Major
(主版本号):当做了不兼容的 API 修改时。Minor
(次版本号):当新增了功能时,且向后兼容。Patch
(修订号):当做了向后兼容的 bug 修复时。
- 发布流程:
- 开发者完成组件开发和评审。
- 开发者更新组件的版本号。
- 开发者发布组件到 npm 或私有仓库。
- 开发者更新 Storybook 文档,并将其部署到静态服务器上。
3.3 沟通机制
建立畅通的沟通渠道,方便团队成员交流和解决问题。
- 沟通工具: 使用 Slack、钉钉、飞书等沟通工具。
- 沟通频率: 定期举行团队会议,讨论组件库的进展和问题。
- 问题反馈: 鼓励团队成员积极反馈问题,并及时解决。
四、总结
今天咱们聊了组件库规范、Storybook 文档管理、多团队协作流程。希望大家能够把这些知识应用到实际项目中,打造一个高质量、易维护、易使用的组件库。
记住,组件库不是一蹴而就的,需要不断地完善和优化。 就像盖房子,地基打好了,才能盖出高楼大厦。组件库规范就是我们的地基,Storybook 是我们的蓝图,多团队协作流程是我们的施工队。 只有地基牢固、蓝图清晰、施工队配合默契,才能盖出令人满意的组件库大厦。
好了,今天的讲座就到这里,谢谢大家! 祝大家都能成为优秀的组件架构师!