Skip to content

构建组件文档站

使用 VitePress 为 Vue 组件库创建专业的文档站点。

项目结构

text
my-ui/
├── docs/                    # 文档目录
│   ├── .vitepress/
│   │   └── config.mts
│   ├── components/          # 组件文档
│   │   ├── button.md
│   │   └── input.md
│   └── index.md
├── src/                     # 组件源码
│   ├── components/
│   │   ├── Button.vue
│   │   └── Input.vue
│   └── index.ts
└── package.json

步骤 1:配置 VitePress

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

export default defineConfig({
  title: 'My UI',
  description: 'Vue 组件库',
  
  vite: {
    resolve: {
      alias: {
        '@': resolve(__dirname, '../src')
      }
    }
  },
  
  themeConfig: {
    logo: '/logo.svg',
    nav: [
      { text: '首页', link: '/' },
      { text: '组件', link: '/components/button' },
      { text: '指南', link: '/guide/' }
    ],
    sidebar: {
      '/components/': [
        {
          text: '基础组件',
          items: [
            { text: 'Button 按钮', link: '/components/button' },
            { text: 'Input 输入框', link: '/components/input' }
          ]
        },
        {
          text: '表单组件',
          items: [
            { text: 'Form 表单', link: '/components/form' }
          ]
        }
      ]
    }
  }
})

步骤 2:创建演示组件

方式一:直接引入组件

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

defineProps<{
  title?: string
  description?: string
}>()

const showCode = ref(false)
</script>

<template>
  <div class="demo-block">
    <div class="demo-preview">
      <slot name="demo" />
    </div>
    
    <div class="demo-meta">
      <div v-if="title" class="demo-title">{{ title }}</div>
      <div v-if="description" class="demo-desc">{{ description }}</div>
    </div>
    
    <div class="demo-actions">
      <button @click="showCode = !showCode">
        {{ showCode ? '隐藏代码' : '显示代码' }}
      </button>
    </div>
    
    <div v-show="showCode" class="demo-code">
      <slot name="code" />
    </div>
  </div>
</template>

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

.demo-preview {
  padding: 1.5rem;
  background: var(--vp-c-bg);
}

.demo-meta {
  padding: 0 1.5rem;
  border-top: 1px solid var(--vp-c-divider);
}

.demo-title {
  font-weight: 600;
  padding: 0.75rem 0 0.25rem;
}

.demo-desc {
  color: var(--vp-c-text-2);
  font-size: 0.875rem;
  padding-bottom: 0.75rem;
}

.demo-actions {
  border-top: 1px solid var(--vp-c-divider);
  text-align: center;
}

.demo-actions button {
  padding: 0.5rem 1rem;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--vp-c-text-2);
  font-size: 0.875rem;
}

.demo-actions button:hover {
  color: var(--vp-c-brand-1);
}

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

方式二:使用插件

安装 vitepress-theme-demoblock

bash
npm install vitepress-theme-demoblock -D
ts
// .vitepress/config.mts
import demoblock from 'vitepress-theme-demoblock'

export default defineConfig({
  markdown: {
    config: (md) => {
      md.use(demoblock)
    }
  }
})

步骤 3:编写组件文档

markdown
<!-- docs/components/button.md -->
---
title: Button 按钮
---

# Button 按钮

常用的操作按钮。

## 基础用法

使用 `type` 属性来定义按钮的样式。

<script setup>
import { Button } from '@/components'
</script>

<div class="demo">
  <Button>默认按钮</Button>
  <Button type="primary">主要按钮</Button>
  <Button type="success">成功按钮</Button>
  <Button type="warning">警告按钮</Button>
  <Button type="danger">危险按钮</Button>
</div>

\`\`\`vue
<template>
  <Button>默认按钮</Button>
  <Button type="primary">主要按钮</Button>
  <Button type="success">成功按钮</Button>
  <Button type="warning">警告按钮</Button>
  <Button type="danger">危险按钮</Button>
</template>

<script setup>
import { Button } from 'my-ui'
</script>
\`\`\`

## 禁用状态

使用 `disabled` 属性来控制按钮是否可用。

<div class="demo">
  <Button disabled>禁用按钮</Button>
  <Button type="primary" disabled>禁用按钮</Button>
</div>

\`\`\`vue
<Button disabled>禁用按钮</Button>
<Button type="primary" disabled>禁用按钮</Button>
\`\`\`

## API

### Props

| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|------|------|------|--------|--------|
| type | 按钮类型 | string | primary / success / warning / danger | — |
| size | 尺寸 | string | large / small | — |
| disabled | 是否禁用 | boolean | — | false |
| loading | 是否加载中 | boolean | — | false |

### Events

| 事件名 | 说明 | 参数 |
|--------|------|------|
| click | 点击按钮时触发 | event |

### Slots

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

<style>
.demo {
  padding: 1.5rem;
  margin: 1rem 0;
  border: 1px solid var(--vp-c-divider);
  border-radius: 8px;
}
</style>

步骤 4:注册全局组件

ts
// .vitepress/theme/index.ts
import DefaultTheme from 'vitepress/theme'
import { Button, Input, Form } from '../../src/components'

export default {
  extends: DefaultTheme,
  enhanceApp({ app }) {
    // 注册组件
    app.component('Button', Button)
    app.component('Input', Input)
    app.component('Form', Form)
  }
}

步骤 5:自动生成 API 文档

ts
// scripts/gen-component-docs.ts
import { parse } from 'vue-docgen-api'
import fs from 'fs'
import path from 'path'

async function generateDocs(componentPath: string, outputPath: string) {
  const component = await parse(componentPath)
  
  let markdown = `# ${component.displayName || 'Component'}\n\n`
  
  if (component.description) {
    markdown += `${component.description}\n\n`
  }
  
  // Props
  if (component.props?.length) {
    markdown += '## Props\n\n'
    markdown += '| 参数 | 说明 | 类型 | 默认值 |\n'
    markdown += '|------|------|------|--------|\n'
    
    for (const prop of component.props) {
      markdown += `| ${prop.name} | ${prop.description || '-'} | ${prop.type?.name || '-'} | ${prop.defaultValue?.value || '-'} |\n`
    }
    
    markdown += '\n'
  }
  
  // Events
  if (component.events?.length) {
    markdown += '## Events\n\n'
    markdown += '| 事件名 | 说明 | 参数 |\n'
    markdown += '|--------|------|------|\n'
    
    for (const event of component.events) {
      markdown += `| ${event.name} | ${event.description || '-'} | - |\n`
    }
    
    markdown += '\n'
  }
  
  // Slots
  if (component.slots?.length) {
    markdown += '## Slots\n\n'
    markdown += '| 插槽名 | 说明 |\n'
    markdown += '|--------|------|\n'
    
    for (const slot of component.slots) {
      markdown += `| ${slot.name} | ${slot.description || '-'} |\n`
    }
  }
  
  fs.writeFileSync(outputPath, markdown)
}

// 使用
generateDocs('src/components/Button.vue', 'docs/components/button-api.md')

学习检查清单

  • [ ] 配置了组件库文档结构
  • [ ] 创建了演示组件
  • [ ] 编写了组件文档
  • [ ] 注册了全局组件
  • [ ] 生成了 API 文档

参考链接

贡献者

加载中...

想要成为贡献者?

在 CNB 上参与贡献