优秀的组件文档能够:
- 降低学习成本 - 新成员快速上手
- 提升开发效率 - 减少沟通和试错
- 保证一致性 - 统一使用方式
- 促进协作 - 设计与开发共识
| 模块 | 内容 | 优先级 |
|---|
| 概述 | 组件用途和使用场景 | 必须 |
| 基础用法 | 最简单的使用示例 | 必须 |
| API 文档 | Props/Events/Slots 说明 | 必须 |
| 变体展示 | 不同状态和配置 | 必须 |
| 设计指南 | 何时使用/不使用 | 推荐 |
| 可访问性 | A11y 指南 | 推荐 |
| 更新日志 | 版本变化记录 | 推荐 |
# Button 按钮
按钮用于触发一个操作或事件,如提交表单、打开对话框等。
## 何时使用
- 需要用户主动触发的操作
- 表单提交
- 对话框操作
- 页面跳转
## 基础用法
最简单的按钮只需要设置 `label` 属性。
```vue
<Button label="点击我" />
通过 variant 属性设置按钮类型。
| 类型 | 用途 |
|---|
| primary | 主要操作 |
| secondary | 次要操作 |
| outline | 轻量操作 |
| danger | 危险操作 |
| 属性 | 说明 | 类型 | 默认值 |
|---|
| variant | 按钮类型 | 'primary' | 'secondary' | 'outline' | 'danger' | 'primary' |
| size | 按钮尺寸 | 'sm' | 'md' | 'lg' | 'md' |
| disabled | 禁用状态 | boolean | false |
| loading | 加载状态 | boolean | false |
| 事件 | 说明 | 参数 |
|---|
| click | 点击时触发 | (event: MouseEvent) |
## Storybook 集成
### 基础配置
```javascript
// .storybook/main.js
export default {
stories: ['../src/**/*.stories.@(js|jsx|ts|tsx|mdx)'],
addons: [
'@storybook/addon-essentials',
'@storybook/addon-a11y',
'@storybook/addon-interactions'
],
framework: {
name: '@storybook/vue3-vite',
options: {}
},
docs: {
autodocs: 'tag'
}
}
// Button.stories.ts
import type { Meta, StoryObj } from '@storybook/vue3'
import Button from './Button.vue'
const meta: Meta<typeof Button> = {
title: 'Components/Button',
component: Button,
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['primary', 'secondary', 'outline', 'danger'],
description: '按钮类型'
},
size: {
control: 'radio',
options: ['sm', 'md', 'lg'],
description: '按钮尺寸'
},
disabled: {
control: 'boolean',
description: '禁用状态'
}
}
}
export default meta
type Story = StoryObj<typeof Button>
// 默认状态
export const Default: Story = {
args: {
label: '默认按钮'
}
}
// 主要按钮
export const Primary: Story = {
args: {
variant: 'primary',
label: '主要按钮'
}
}
// 所有变体展示
export const AllVariants: Story = {
render: () => ({
components: { Button },
template: `
<div class="flex gap-4">
<Button variant="primary" label="Primary" />
<Button variant="secondary" label="Secondary" />
<Button variant="outline" label="Outline" />
<Button variant="danger" label="Danger" />
</div>
`
})
}
// 加载状态
export const Loading: Story = {
args: {
loading: true,
label: '加载中'
}
}
// Button.mdx
import { Meta, Story, Canvas, ArgsTable } from '@storybook/blocks'
import * as ButtonStories from './Button.stories'
<Meta of={ButtonStories} />
# Button 按钮
按钮是最基础的交互组件,用于触发用户操作。
## 设计原则
- 每个页面最多一个主要按钮
- 按钮文字应该清晰表达操作意图
- 危险操作需要二次确认
## 基础用法
<Canvas of={ButtonStories.Default} />
## 按钮变体
<Canvas of={ButtonStories.AllVariants} />
## API 参考
<ArgsTable of={ButtonStories} />
## 可访问性
- 使用语义化的 `<button>` 标签
- 禁用状态设置 `aria-disabled`
- 加载状态设置 `aria-busy`
// Button.vue
export interface ButtonProps {
/**
* 按钮类型
* @default 'primary'
*/
variant?: 'primary' | 'secondary' | 'outline' | 'danger'
/**
* 按钮尺寸
* @default 'md'
*/
size?: 'sm' | 'md' | 'lg'
/**
* 是否禁用
* @default false
*/
disabled?: boolean
/**
* 是否加载中
* @default false
*/
loading?: boolean
/**
* 按钮文字
*/
label?: string
}
export interface ButtonEmits {
/**
* 点击事件
*/
(e: 'click', event: MouseEvent): void
}
// .vitepress/config.js
export default {
title: '组件库文档',
themeConfig: {
sidebar: [
{
text: '开始使用',
items: [
{ text: '介绍', link: '/guide/introduction' },
{ text: '快速开始', link: '/guide/quickstart' }
]
},
{
text: '组件',
items: [
{ text: 'Button 按钮', link: '/components/button' },
{ text: 'Input 输入框', link: '/components/input' },
{ text: 'Modal 对话框', link: '/components/modal' }
]
}
]
}
}
<template>
<div class="playground">
<div class="preview">
<component :is="component" v-bind="props" />
</div>
<div class="controls">
<label v-for="(value, key) in props" :key="key">
<span>{{ key }}</span>
<input
v-model="props[key]"
:type="getInputType(key)"
/>
</label>
</div>
<div class="code">
<pre>{{ generatedCode }}</pre>
</div>
</div>
</template>
<script setup>
const props = reactive({
variant: 'primary',
size: 'md',
disabled: false,
label: '按钮'
})
const generatedCode = computed(() => {
const attrs = Object.entries(props)
.filter(([_, v]) => v !== false && v !== '')
.map(([k, v]) => {
if (typeof v === 'boolean') return `:${k}="true"`
return `${k}="${v}"`
})
.join(' ')
return `<Button ${attrs} />`
})
</script>
# 组件目录结构
src/components/Button/
├── Button.vue # 组件实现
├── Button.test.ts # 单元测试
├── Button.stories.ts # Storybook Stories
├── Button.md # 使用文档
└── index.ts # 导出
# .github/workflows/docs.yml
name: Docs Check
on: [pull_request]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 检查组件是否有文档
run: |
for component in src/components/*/; do
if [ ! -f "${component}*.stories.ts" ]; then
echo "缺少 Story: ${component}"
exit 1
fi
done
- name: 构建文档
run: npm run docs:build
- name: 检查链接
run: npm run docs:check-links
| 原则 | 说明 |
|---|
| 示例先行 | 先看效果,再看 API |
| 代码可复制 | 所有示例可直接使用 |
| 保持更新 | 代码改动同步更新文档 |
| 覆盖边界 | 展示各种状态和异常情况 |
| 设计意图 | 说明何时使用/不使用 |
优秀的组件文档需要:
- 结构清晰 - 从基础到高级循序渐进
- 示例丰富 - 覆盖各种使用场景
- API 完整 - Props/Events/Slots 详细说明
- 可交互 - 在线修改预览效果
- 持续维护 - 与代码保持同步
投入文档建设,是对团队协作效率的长期投资。