组件库文档化最佳实践完全指南

HTMLPAGE 团队
20分钟 分钟阅读

系统讲解前端组件库文档的设计与实现,包括文档结构、API 文档、使用示例、交互演示等核心内容,帮助构建高质量的组件文档。

#组件文档 #Storybook #API文档 #设计系统 #开发规范

组件文档的价值

优秀的组件文档能够:

  • 降低学习成本 - 新成员快速上手
  • 提升开发效率 - 减少沟通和试错
  • 保证一致性 - 统一使用方式
  • 促进协作 - 设计与开发共识

文档内容结构

完整的组件文档应包含

模块内容优先级
概述组件用途和使用场景必须
基础用法最简单的使用示例必须
API 文档Props/Events/Slots 说明必须
变体展示不同状态和配置必须
设计指南何时使用/不使用推荐
可访问性A11y 指南推荐
更新日志版本变化记录推荐

文档模板

# Button 按钮

按钮用于触发一个操作或事件,如提交表单、打开对话框等。

## 何时使用

- 需要用户主动触发的操作
- 表单提交
- 对话框操作
- 页面跳转

## 基础用法

最简单的按钮只需要设置 `label` 属性。

```vue
<Button label="点击我" />

按钮类型

通过 variant 属性设置按钮类型。

类型用途
primary主要操作
secondary次要操作
outline轻量操作
danger危险操作

API

Props

属性说明类型默认值
variant按钮类型'primary' | 'secondary' | 'outline' | 'danger''primary'
size按钮尺寸'sm' | 'md' | 'lg''md'
disabled禁用状态booleanfalse
loading加载状态booleanfalse

Events

事件说明参数
click点击时触发(event: MouseEvent)

Slots

插槽说明
default按钮内容
icon图标插槽

## 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'
  }
}

编写 Stories

// 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: '加载中'
  }
}

MDX 文档增强

// 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`

API 文档自动生成

使用 TypeScript 类型生成

// 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 文档站

// .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            # 导出

CI 检查

# .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
代码可复制所有示例可直接使用
保持更新代码改动同步更新文档
覆盖边界展示各种状态和异常情况
设计意图说明何时使用/不使用

总结

优秀的组件文档需要:

  1. 结构清晰 - 从基础到高级循序渐进
  2. 示例丰富 - 覆盖各种使用场景
  3. API 完整 - Props/Events/Slots 详细说明
  4. 可交互 - 在线修改预览效果
  5. 持续维护 - 与代码保持同步

投入文档建设,是对团队协作效率的长期投资。