Skip to content

组件库文档

本教程将详细介绍如何为 Vue 组件库搭建一个专业、美观的文档站点。

项目规划

目录结构

一个完整的组件库文档项目结构:

my-ui/
├── src/                     # 组件源码
│   ├── components/
│   │   ├── Button/
│   │   │   ├── index.ts
│   │   │   ├── Button.vue
│   │   │   └── Button.test.ts
│   │   ├── Input/
│   │   └── index.ts
│   └── index.ts
├── docs/                    # 文档目录
│   ├── .vitepress/
│   │   ├── config.mts
│   │   └── theme/
│   │       ├── index.ts
│   │       └── components/
│   │           ├── DemoPreview.vue
│   │           ├── ApiTable.vue
│   │           └── ComponentCard.vue
│   ├── components/          # 组件文档
│   │   ├── button.md
│   │   ├── input.md
│   │   └── index.md
│   ├── guide/               # 指南文档
│   │   ├── getting-started.md
│   │   ├── installation.md
│   │   └── theming.md
│   ├── public/
│   │   └── logo.svg
│   └── index.md
├── package.json
└── vite.config.ts

基础配置

VitePress 配置

ts
// docs/.vitepress/config.mts
import { defineConfig } from 'vitepress'
import { resolve } from 'path'

export default defineConfig({
  title: 'My UI',
  description: '一个现代化的 Vue 3 组件库',
  lang: 'zh-CN',
  
  // 配置别名,方便在文档中引入组件
  vite: {
    resolve: {
      alias: {
        '@': resolve(__dirname, '../../src')
      }
    }
  },
  
  themeConfig: {
    logo: '/logo.svg',
    
    nav: [
      { text: '首页', link: '/' },
      { text: '指南', link: '/guide/getting-started' },
      { text: '组件', link: '/components/' },
      {
        text: '相关链接',
        items: [
          { text: 'GitHub', link: 'https://github.com/user/my-ui' },
          { text: 'npm', link: 'https://npmjs.com/package/my-ui' }
        ]
      }
    ],
    
    sidebar: {
      '/guide/': [
        {
          text: '开始',
          items: [
            { text: '快速开始', link: '/guide/getting-started' },
            { text: '安装', link: '/guide/installation' },
            { text: '主题定制', link: '/guide/theming' }
          ]
        }
      ],
      '/components/': [
        {
          text: '基础组件',
          collapsed: false,
          items: [
            { text: 'Button 按钮', link: '/components/button' },
            { text: 'Input 输入框', link: '/components/input' },
            { text: 'Icon 图标', link: '/components/icon' }
          ]
        },
        {
          text: '表单组件',
          collapsed: false,
          items: [
            { text: 'Form 表单', link: '/components/form' },
            { text: 'Select 选择器', link: '/components/select' }
          ]
        }
      ]
    },
    
    search: {
      provider: 'local'
    },
    
    outline: {
      level: [2, 3],
      label: '目录'
    }
  }
})

组件演示系统

DemoPreview 组件

创建一个可交互的组件演示容器:

vue
<!-- docs/.vitepress/theme/components/DemoPreview.vue -->
<script setup lang="ts">
import { ref } from 'vue'

interface Props {
  title?: string
  description?: string
}

const props = withDefaults(defineProps&lt;Props&gt;(), {
  title: '',
  description: ''
})

const showCode = ref(false)
const copied = ref(false)

const copyCode = async () => {
  const codeEl = document.querySelector('.demo-code pre code')
  if (codeEl) {
    await navigator.clipboard.writeText(codeEl.textContent || '')
    copied.value = true
    setTimeout(() => {
      copied.value = false
    }, 2000)
  }
}
</script>

<template>
  <div class="demo-preview">
    <div v-if="title || description" class="demo-header">
      <h4 v-if="title" class="demo-title">{{ title }}</h4>
      <p v-if="description" class="demo-desc">{{ description }}</p>
    </div>
    
    <div class="demo-container">
      <slot name="demo" />
    </div>
    
    <div class="demo-actions">
      <button 
        class="action-btn" 
        :class="{ active: showCode }"
        @click="showCode = !showCode"
      >
        {{ showCode ? '隐藏代码' : '显示代码' }}
      </button>
      <button class="action-btn" @click="copyCode">
        {{ copied ? '已复制!' : '复制代码' }}
      </button>
    </div>
    
    <div v-show="showCode" class="demo-code">
      <slot name="code" />
    </div>
  </div>
</template>

<style scoped>
.demo-preview {
  margin: 24px 0;
  border: 1px solid var(--vp-c-divider);
  border-radius: 12px;
  overflow: hidden;
}

.demo-header {
  padding: 16px 20px;
  border-bottom: 1px solid var(--vp-c-divider);
  background: var(--vp-c-bg-soft);
}

.demo-title {
  margin: 0 0 4px;
  font-size: 16px;
  font-weight: 600;
  color: var(--vp-c-text-1);
}

.demo-desc {
  margin: 0;
  font-size: 14px;
  color: var(--vp-c-text-2);
}

.demo-container {
  padding: 32px;
  background: var(--vp-c-bg);
}

.demo-actions {
  display: flex;
  gap: 8px;
  padding: 12px 16px;
  border-top: 1px solid var(--vp-c-divider);
  background: var(--vp-c-bg-soft);
}

.action-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border: 1px solid var(--vp-c-divider);
  border-radius: 6px;
  background: var(--vp-c-bg);
  color: var(--vp-c-text-2);
  font-size: 13px;
  cursor: pointer;
  transition: all 0.25s ease;
}

.action-btn:hover {
  border-color: var(--vp-c-brand-1);
  color: var(--vp-c-brand-1);
}

.demo-code {
  border-top: 1px solid var(--vp-c-divider);
  background: var(--vp-code-block-bg);
}
</style>

在文档中使用

在组件文档中使用 DemoPreview:

markdown
# Button 按钮

常用的操作按钮,提供多种样式和尺寸。

## 基础用法

<DemoPreview title="基础按钮" description="使用 type 属性定义按钮样式">
  <template #demo>
    <div class="button-demo">
      <Button>默认按钮</Button>
      <Button type="primary">主要按钮</Button>
    </div>
  </template>
  <template #code>

```vue
<template>
  <Button>默认按钮</Button>
  <Button type="primary">主要按钮</Button>
</template>
```

  </template>
</DemoPreview>

注意

在 Markdown 中使用组件时,确保代码块中的 Vue 模板正确缩进,并且闭合标签正确。

API 文档组件

ApiTable 组件

用于展示组件 API 文档的表格组件:

vue
<!-- docs/.vitepress/theme/components/ApiTable.vue -->
<script setup lang="ts">
interface PropItem {
  name: string
  description: string
  type: string
  default?: string
  required?: boolean
}

interface Props {
  title?: string
  data: PropItem[]
}

defineProps&lt;Props&gt;()
</script>

<template>
  <div class="api-table">
    <h4 v-if="title" class="api-title">{{ title }}</h4>
    <table>
      <thead>
        <tr>
          <th>属性名</th>
          <th>说明</th>
          <th>类型</th>
          <th>默认值</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="item in data" :key="item.name">
          <td>
            <code class="prop-name">{{ item.name }}</code>
            <span v-if="item.required" class="required-tag">必填</span>
          </td>
          <td>{{ item.description }}</td>
          <td><code class="type-code">{{ item.type }}</code></td>
          <td>
            <code v-if="item.default" class="default-code">{{ item.default }}</code>
            <span v-else class="empty">-</span>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<style scoped>
.api-table {
  margin: 24px 0;
}

.api-title {
  font-size: 18px;
  font-weight: 600;
  color: var(--vp-c-text-1);
  margin: 0 0 16px;
}

.api-table table {
  width: 100%;
  border-collapse: collapse;
  border-radius: 8px;
  overflow: hidden;
}

.api-table th,
.api-table td {
  padding: 12px 16px;
  text-align: left;
  border-bottom: 1px solid var(--vp-c-divider);
}

.api-table th {
  background: var(--vp-c-bg-soft);
  font-weight: 600;
}

.prop-name {
  padding: 2px 8px;
  background: var(--vp-c-brand-soft);
  color: var(--vp-c-brand-1);
  border-radius: 4px;
  font-size: 13px;
}

.required-tag {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  background: #fef3c7;
  color: #b45309;
  border-radius: 4px;
  font-size: 11px;
}
</style>

使用 API 表格

markdown
## API

### Props

<ApiTable :data="[
  { name: 'type', description: '按钮类型', type: 'string', default: 'default' },
  { name: 'size', description: '按钮尺寸', type: 'string', default: 'medium' },
  { name: 'disabled', description: '是否禁用', type: 'boolean', default: 'false' }
]" />

主题定制

CSS 变量

组件库使用 CSS 变量实现主题定制:

css
/* docs/.vitepress/theme/style.css */

:root {
  /* 品牌色 */
  --my-primary-color: #6366f1;
  --my-success-color: #10b981;
  --my-warning-color: #f59e0b;
  --my-danger-color: #ef4444;
  
  /* 边框圆角 */
  --my-border-radius-sm: 4px;
  --my-border-radius-md: 8px;
  --my-border-radius-lg: 12px;
  
  /* 阴影 */
  --my-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
  --my-shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
  --my-shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
}

.dark {
  --my-primary-color: #818cf8;
  --my-success-color: #34d399;
  --my-warning-color: #fbbf24;
  --my-danger-color: #f87171;
}

主题配置页面

创建主题配置演示页面,让用户实时预览主题变化:

vue
<!-- docs/.vitepress/theme/components/ThemeCustomizer.vue -->
<script setup>
import { ref, watch } from 'vue'

const primaryColor = ref('#6366f1')
const borderRadius = ref(8)

watch([primaryColor, borderRadius], ([color, radius]) => {
  document.documentElement.style.setProperty('--my-primary-color', color)
  document.documentElement.style.setProperty('--my-border-radius-md', radius + 'px')
})
</script>

<template>
  <div class="theme-customizer">
    <div class="customizer-item">
      <label>主题色</label>
      <input type="color" v-model="primaryColor" />
    </div>
    <div class="customizer-item">
      <label>圆角大小: {{ borderRadius }}px</label>
      <input type="range" v-model="borderRadius" min="0" max="20" />
    </div>
  </div>
</template>

自动生成 API 文档

使用 JSDoc 注释

在组件源码中添加 JSDoc 注释:

vue
<script setup lang="ts">
/**
 * Button 组件
 * @component Button
 * @description 常用的操作按钮组件
 */

interface ButtonProps {
  /**
   * 按钮类型
   * @values default, primary, success, warning, danger
   */
  type?: 'default' | 'primary' | 'success' | 'warning' | 'danger'
  
  /**
   * 按钮尺寸
   * @values small, medium, large
   */
  size?: 'small' | 'medium' | 'large'
  
  /**
   * 是否禁用
   */
  disabled?: boolean
}

const props = withDefaults(defineProps&lt;ButtonProps&gt;(), {
  type: 'default',
  size: 'medium',
  disabled: false
})
</script>

完整组件文档模板

markdown
---
title: Button 按钮
description: 常用的操作按钮组件
---

# Button 按钮

常用的操作按钮,提供多种样式、尺寸和状态。

## 何时使用

- 需要用户执行某个操作时
- 表单提交、确认/取消等场景
- 需要强调某个操作时

## 代码演示

### 基础用法

最基本的按钮用法。

```vue
<template>
  <Button>默认按钮</Button>
  <Button type="primary">主要按钮</Button>
  <Button type="success">成功按钮</Button>
</template>

按钮尺寸

提供三种尺寸:小、中、大。

vue
<template>
  <Button size="small">小按钮</Button>
  <Button size="medium">中按钮</Button>
  <Button size="large">大按钮</Button>
</template>

禁用状态

按钮不可用状态。

vue
<template>
  <Button disabled>禁用按钮</Button>
</template>

加载状态

显示加载中的按钮。

vue
<template>
  <Button loading>加载中</Button>
</template>

API

Props

属性名说明类型默认值
type按钮类型stringdefault
size按钮尺寸stringmedium
disabled是否禁用booleanfalse
loading是否加载中booleanfalse

Events

事件名说明回调参数
click点击按钮时触发(event: MouseEvent)

Slots

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

设计指南

按钮层级

  1. 主要按钮:用于主要操作,一个页面最多一个
  2. 次要按钮:用于次要操作
  3. 文字按钮:用于最低优先级的操作

最佳实践

  • ✅ 保持按钮文案简洁明了
  • ✅ 危险操作使用红色警示
  • ❌ 不要在一个区域使用过多按钮
  • ❌ 不要使用过长的按钮文案

## 部署与发布

### 自动化部署

```yaml
# .github/workflows/docs.yml
name: Deploy Docs

on:
  push:
    branches: [main]
    paths:
      - 'docs/**'
      - 'src/**'

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'
      
      - run: npm ci
      - run: npm run docs:build
      
      - uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: docs/.vitepress/dist

最佳实践总结

实践说明
一致的文档结构每个组件文档遵循相同格式
丰富的示例提供多种使用场景
清晰的 API完整记录 props、events、slots
可交互演示让用户直接体验组件
自动化部署每次提交自动更新文档

下一步

🎯 进阶挑战

完成基础教程后,尝试以下挑战来提升你的技能:

挑战 1:组件 Props 编辑器 ⭐⭐⭐

目标:创建一个可视化的 Props 编辑器,实时预览组件变化。

提示

  • 使用 Vue 的 defineProps 类型推断
  • 动态渲染表单控件
  • 双向绑定实现实时预览

参考思路

vue
<script setup>
const propsConfig = [
  { name: 'type', type: 'select', options: ['default', 'primary', 'danger'] },
  { name: 'size', type: 'select', options: ['small', 'medium', 'large'] },
  { name: 'disabled', type: 'boolean' }
]

const currentProps = reactive({})
</script>

挑战 2:组件代码在线编辑 ⭐⭐⭐⭐

目标:集成 Monaco Editor,实现在线编辑组件代码。

提示

  • 使用 @monaco-editor/loader
  • 实现代码热更新
  • 添加错误提示

挑战 3:组件主题切换器 ⭐⭐⭐

目标:创建实时主题切换器,让用户自定义组件库主题。

提示

  • 使用 CSS 变量
  • 实时预览主题变化
  • 导出主题配置

挑战 4:组件使用统计 ⭐⭐⭐

目标:统计每个组件文档的访问量,展示热门组件。

提示

  • 使用数据加载器读取访问数据
  • 创建热度排行榜
  • 可视化展示统计数据

挑战 5:组件版本差异对比 ⭐⭐⭐⭐

目标:展示不同版本组件的 API 差异。

提示

  • 使用 diff 算法对比
  • 高亮变化部分
  • 添加版本选择器

挑战 6:组件可访问性检测 ⭐⭐⭐⭐

目标:为组件演示添加 a11y 检测功能。

提示

  • 使用 axe-core 库
  • 在演示容器中运行检测
  • 展示可访问性问题列表

贡献者

加载中...

想要成为贡献者?

在 CNB 上参与贡献