npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vue-doc-readme

v1.0.6

Published

Vue3 报表说明组件,支持 Markdown 展示和 PDF 导出,支持零配置自动识别

Readme

vue-doc-readme

Vue3 文档说明组件,支持 Markdown 展示和 PDF 导出,支持零配置自动识别。

✨ 特性

  • 🚀 轻量级:核心代码 < 500 行
  • 🔒 类型安全:完整的 TypeScript 支持
  • 🎨 美观:集成 Ant Design Vue
  • 📦 灵活:支持组件和插件两种使用方式
  • 💾 智能缓存:自动缓存已加载的文档
  • 📄 PDF 导出:一键导出为 PDF 文件
  • 🖨️ 打印支持:优化的打印样式
  • 🔧 可配置:丰富的配置选项和插槽
  • 🛡️ 安全:XSS 防护(DOMPurify)

📦 安装

npm install vue-doc-readme
# 或
pnpm add vue-doc-readme
# 或
yarn add vue-doc-readme

Peer Dependencies

{
  "vue": ">=3.0.10",
  "ant-design-vue": ">=2.1.3"
}

🚀 快速开始

方式一:零配置模式(最简单,推荐)⭐

完全零配置! 组件会自动从URL路径最后一段获取报表ID:

<template>
  <div>
    <h1>日报统计</h1>
    <!-- 自动从URL获取ID,例如 /system/one/report1 → report1 -->
    <ReportReadmeButton />
  </div>
</template>

<script setup lang="ts">
import { ReportReadmeButton } from 'vue-doc-readme'
import 'vue-doc-readme/style.css'
</script>

URL示例

  • /system/one/report1 → 自动获取 report1
  • /reports/daily/analytics → 自动获取 analytics
  • /admin/report-123 → 自动获取 report-123

当然,你也可以手动指定:

<template>
  <!-- 手动指定ID(优先级更高) -->
  <ReportReadmeButton report-id="custom-report-001" />
</template>

就这么简单! 🎉

方式二:直接传入Markdown内容

如果你已经有markdown字符串,无需调用API:

<template>
  <ReportReadmeButton :markdown="mdContent" />
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { ReportReadmeButton } from 'vue-doc-readme'
import 'vue-doc-readme/style.css'

const mdContent = ref(`
# 使用说明

## 概述
这是报表的使用说明...

## 功能特点
1. 数据统计
2. 图表展示
3. 导出功能
`)
</script>

优先级markdown prop > API获取

方式三:插件模式(推荐用于全局配置)

基础配置

// main.ts
import { createApp } from 'vue'
import Antd from 'ant-design-vue'
import 'ant-design-vue/dist/reset.css'
import ReportReadmePlugin from 'vue-doc-readme'
import 'vue-doc-readme/style.css'
import App from './App.vue'

const app = createApp(App)

app.use(Antd)
app.use(ReportReadmePlugin, {
  apiUrl: '/api/report/doc',       // 默认API地址
  cacheDuration: 1800000,          // 缓存30分钟
  showExportBtn: true,             // 显示导出按钮
  showPrintBtn: true               // 显示打印按钮
})

app.mount('#app')

集成宿主系统的请求配置 ⭐

如果你的项目有统一的请求配置(如 utils/request.js),可以传入自定义请求函数:

// main.ts
import { createApp } from 'vue'
import ReportReadmePlugin from 'vue-doc-readme'
import 'vue-doc-readme/style.css'
import request from './utils/request'  // 你的请求工具
import App from './App.vue'

const app = createApp(App)

app.use(ReportReadmePlugin, {
  apiUrl: '/api/report/doc',
  // 使用宿主系统的request(会自动带上baseURL、拦截器等配置)
  requestFn: async (url, options) => {
    const response = await request({
      url,
      method: options?.method || 'GET',
      headers: options?.headers
    })
    return response.data  // 返回格式: { resultData, resultStatus, code }
  }
})

app.mount('#app')

示例:集成axios

// utils/request.js
import axios from 'axios'

const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API,
  timeout: 5000
})

// 请求拦截器
service.interceptors.request.use(
  config => {
    const token = localStorage.getItem('token')
    if (token) {
      config.headers['Authorization'] = `Bearer ${token}`
    }
    return config
  }
)

// 响应拦截器
service.interceptors.response.use(
  response => response.data,
  error => Promise.reject(error)
)

export default service
// main.ts
import ReportReadmePlugin from 'vue-doc-readme'
import request from './utils/request'

app.use(ReportReadmePlugin, {
  requestFn: async (url) => {
    // request会自动带上baseURL、token等配置
    return await request.get(url)
  }
})

好处

  • ✅ 统一使用项目的请求配置(baseURL、超时、拦截器)
  • ✅ 自动带上token等认证信息
  • ✅ 统一错误处理
  • ✅ 复用现有请求工具

然后在任意组件中使用:

<template>
  <ReportReadme report-id="daily-report-001" />
</template>

方式四:弹窗模式

手动控制弹窗的显示和隐藏:

<template>
  <div>
    <a-button @click="showModal">查看说明</a-button>
    
    <ReportReadmeModal
      v-model:open="modalVisible"
      report-id="daily-report-001"
      modal-title="日报使用说明"
      :modal-width="900"
    />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { ReportReadmeModal } from 'vue-doc-readme'
import '@your-org/report-readme/style.css'

const modalVisible = ref(false)

const showModal = () => {
  modalVisible.value = true
}
</script>

方式五:内嵌组件模式

直接在页面中展示(不使用弹窗):

<template>
  <ReportReadme
    report-id="daily-report-001"
    api-url="/api/report/doc"
    :auto-load="true"
    :cache="true"
    @load="handleLoad"
    @error="handleError"
  />
</template>

<script setup lang="ts">
import { ReportReadme } from 'vue-doc-readme'
import '@your-org/report-readme/style.css'
import type { ReportDoc } from '@your-org/report-readme'

const handleLoad = (doc: ReportDoc) => {
  console.log('加载成功:', doc)
}

const handleError = (error: Error) => {
  console.error('加载失败:', error)
}
</script>

📝 API

ReportReadmeButton(快捷按钮组件)

最简单的使用方式,一个按钮搞定一切。

Props

| 参数 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | reportId | 报表ID(必需) | string | - | | buttonText | 按钮文字 | string | 使用说明 | | buttonType | 按钮类型 | 'default' \| 'primary' \| 'dashed' \| 'link' \| 'text' | default | | buttonSize | 按钮尺寸 | 'large' \| 'middle' \| 'small' | middle | | buttonIcon | 自定义按钮图标 | Component | QuestionCircleOutlined | | modalTitle | 弹窗标题 | string | 报表说明 | | modalWidth | 弹窗宽度 | string \| number | 900 | | apiUrl | API地址 | string | /api/report/doc | | autoLoad | 是否自动加载 | boolean | true | | cache | 是否启用缓存 | boolean | true | | cacheDuration | 缓存时长(毫秒) | number | 1800000 (30分钟) | | showExportBtn | 是否显示导出按钮 | boolean | true | | showPrintBtn | 是否显示打印按钮 | boolean | true | | headers | 自定义请求头 | Record<string, string> | {} |

Events

| 事件 | 说明 | 回调参数 | | --- | --- | --- | | click | 点击按钮 | () => void | | load | 加载成功 | (doc: ReportDoc) => void | | error | 加载失败 | (error: Error) => void | | exportSuccess | 导出成功 | (filename: string) => void | | exportError | 导出失败 | (error: Error) => void |

使用示例

<template>
  <!-- 零配置:自动从URL获取ID -->
  <ReportReadmeButton />
  
  <!-- 手动指定ID -->
  <ReportReadmeButton report-id="daily-report-001" />
  
  <!-- 自定义样式(同时自动获取ID) -->
  <ReportReadmeButton
    button-text="帮助文档"
    button-type="primary"
    button-size="small"
    modal-title="日报使用指南"
    :modal-width="1000"
  />
  
  <!-- 监听事件 -->
  <ReportReadmeButton
    @click="handleClick"
    @load="handleLoad"
    @error="handleError"
  />
</template>

工作原理

// URL: /system/reports/daily-report-001
<ReportReadmeButton />
// 等同于
<ReportReadmeButton report-id="daily-report-001" />

// 如果手动指定,会优先使用指定的ID
<ReportReadmeButton report-id="custom-id" />
// 使用 custom-id,忽略URL

ReportReadmeModal(弹窗组件)

手动控制弹窗的显示隐藏。

Props

继承 ReportReadme 的所有Props,额外增加:

| 参数 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | open | 是否显示弹窗(v-model) | boolean | false | | modalTitle | 弹窗标题 | string | 报表说明 | | modalWidth | 弹窗宽度 | string \| number | 900 |

Events

继承 ReportReadme 的所有Events,额外增加:

| 事件 | 说明 | 回调参数 | | --- | --- | --- | | update:open | 弹窗显示状态变化 | (value: boolean) => void |


ReportReadme(基础组件)

内嵌展示模式,直接在页面中渲染。

Props

| 参数 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | reportId | 报表ID(必需) | string | - | | apiUrl | API地址 | string | /api/report/doc | | autoLoad | 是否自动加载 | boolean | true | | cache | 是否启用缓存 | boolean | true | | cacheDuration | 缓存时长(毫秒) | number | 1800000 (30分钟) | | showExportBtn | 是否显示导出按钮 | boolean | true | | showPrintBtn | 是否显示打印按钮 | boolean | true | | headers | 自定义请求头 | Record<string, string> | {} |

Events

| 事件 | 说明 | 回调参数 | | --- | --- | --- | | load | 加载成功 | (doc: ReportDoc) => void | | error | 加载失败 | (error: Error) => void | | exportSuccess | 导出成功 | (filename: string) => void | | exportError | 导出失败 | (error: Error) => void |

Slots

| 插槽 | 说明 | | --- | --- | | header | 自定义头部 | | loading | 自定义加载状态 | | error | 自定义错误显示 | | footer | 自定义底部 |

🎨 高级用法

快捷按钮自定义

<template>
  <!-- 自定义按钮样式 -->
  <ReportReadmeButton
    report-id="daily-report-001"
    button-text="查看帮助"
    button-type="primary"
    button-size="large"
  />
  
  <!-- 自定义弹窗内容 -->
  <ReportReadmeButton report-id="daily-report-001">
    <template #header>
      <div class="custom-header">
        <a-tag color="blue">最新版本 v2.0</a-tag>
      </div>
    </template>
    
    <template #footer>
      <a-divider />
      <p>有疑问?联系客服:400-xxx-xxxx</p>
    </template>
  </ReportReadmeButton>
</template>

自定义加载和错误状态

<template>
  <ReportReadme report-id="daily-report-001">
    <template #loading>
      <div class="custom-loading">
        <a-spin size="large" />
        <p>正在加载报表说明...</p>
      </div>
    </template>

    <template #error="{ error }">
      <a-alert
        type="error"
        :message="error.message"
        show-icon
      />
    </template>
  </ReportReadme>
</template>

自定义头部和底部

<template>
  <ReportReadme report-id="daily-report-001">
    <template #header>
      <div class="custom-header">
        <a-tag color="blue">最新版本</a-tag>
        <span>更新时间: 2026-01-21</span>
      </div>
    </template>

    <template #footer>
      <a-divider />
      <p class="footer-text">
        如有疑问,请联系技术支持
      </p>
    </template>
  </ReportReadme>
</template>

使用 Composables

<script setup lang="ts">
import { ref } from 'vue'
import { useReportDoc, usePdfExport } from 'vue-doc-readme'

const reportId = ref('daily-report-001')

// 数据获取
const {
  data,
  isLoading,
  isError,
  error,
  reload
} = useReportDoc({
  reportId,
  apiUrl: '/api/report/doc',
  autoLoad: true,
  cache: true
})

// PDF导出
const { isExporting, exportToPdf } = usePdfExport()

const handleExport = async () => {
  const element = document.querySelector('.content')
  if (element) {
    await exportToPdf(element as HTMLElement, {
      filename: 'report',
      orientation: 'portrait'
    })
  }
}
</script>

动态切换报表

<template>
  <div>
    <a-space>
      <span>选择报表:</span>
      <a-select v-model:value="currentReportId" style="width: 200px">
        <a-select-option value="report-001">日报</a-select-option>
        <a-select-option value="report-002">周报</a-select-option>
        <a-select-option value="report-003">月报</a-select-option>
      </a-select>
      
      <!-- 按钮会自动跟随reportId变化 -->
      <ReportReadmeButton :report-id="currentReportId" />
    </a-space>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { ReportReadmeButton } from 'vue-doc-readme'

const currentReportId = ref('report-001')
</script>

在表格每行添加说明按钮

<template>
  <a-table :columns="columns" :data-source="data">
    <template #bodyCell="{ column, record }">
      <template v-if="column.key === 'action'">
        <ReportReadmeButton
          :report-id="record.reportId"
          button-text="查看说明"
          button-type="link"
          button-size="small"
        />
      </template>
    </template>
  </a-table>
</template>

<script setup lang="ts">
import { ReportReadmeButton } from 'vue-doc-readme'

const columns = [
  { title: '报表名称', dataIndex: 'name', key: 'name' },
  { title: '类型', dataIndex: 'type', key: 'type' },
  { title: '操作', key: 'action' }
]

const data = [
  { reportId: 'daily-001', name: '日报', type: '统计' },
  { reportId: 'weekly-001', name: '周报', type: '汇总' },
  { reportId: 'monthly-001', name: '月报', type: '分析' }
]
</script>

🔌 后端接口规范

请求

GET /api/report/doc?reportId=xxx

响应格式

{
  resultStatus: 200 | '200',  // 200或'200'表示成功
  msg?: string,               // 响应消息(可选)
  resultData: {
    id: string,
    title: string,
    content: string,  // Markdown格式
    version?: string,
    updateTime?: string,
    author?: string,
    tags?: string[]
  }
}

说明

  • resultStatus:200 或 '200' 字符串都表示成功
  • msg:可选的消息字段,失败时包含错误信息
  • resultData:可以是对象、数组或字符串

示例

成功响应

{
  "resultStatus": 200,
  "msg": "success",
  "resultData": {
    "id": "daily-report-001",
    "title": "日报使用说明",
    "content": "# 日报使用说明\n\n## 1. 概述\n\n本报表用于...",
    "version": "v1.0.0",
    "updateTime": "2026-01-21T10:00:00Z",
    "author": "系统管理员",
    "tags": ["日报", "统计"]
  }
}

{
  "resultStatus": "200",
  "resultData": {
    "id": "daily-report-001",
    "title": "日报使用说明",
    "content": "# 日报使用说明..."
  }
}

失败响应

{
  "resultStatus": 500,
  "msg": "报表不存在"
}

🎯 TypeScript 支持

完整的类型定义:

import type {
  ApiResponse,
  ReportDoc,
  ReportReadmeProps,
  ReportReadmePluginOptions,
  PdfExportOptions
} from 'vue-doc-readme'

// 使用类型
const props: ReportReadmeProps = {
  reportId: 'report-001',
  apiUrl: '/api/report/doc',
  autoLoad: true
}

🔧 缓存管理

import { cacheManager } from 'vue-doc-readme'

// 清除特定缓存
cacheManager.delete('report-doc:report-001')

// 清除所有缓存
cacheManager.clear()

// 检查缓存
const hasCache = cacheManager.has('report-doc:report-001')

// 手动设置缓存
cacheManager.set('custom-key', data, 30 * 60 * 1000)

📱 移动端适配

组件已针对移动端进行优化:

  • 响应式布局
  • 触摸友好的按钮尺寸
  • 优化的字体大小
  • 移动端打印支持

🖨️ 打印样式

打印时自动隐藏工具栏,优化内容显示:

@media print {
  .report-readme__toolbar {
    display: none;
  }
}

🛡️ 安全性

  • XSS防护:使用 DOMPurify 清理 HTML
  • CSP友好:不使用内联脚本
  • 类型安全:完整的 TypeScript 类型检查

📊 性能优化

  • ⚡ 智能缓存:避免重复请求
  • 🎯 按需加载:懒加载 markdown 渲染库
  • 🗜️ 体积优化:Tree-shaking 友好
  • 🔄 虚拟滚动:适用于超长文档(可扩展)

🤝 兼容性

  • Vue 3.3+
  • Ant Design Vue 4.0+
  • 现代浏览器(Chrome, Firefox, Safari, Edge)
  • Node.js 16+

📄 License

MIT

🙋 常见问题

Q: 如何自定义 Markdown 样式?

A: 可以覆盖 .markdown-body 相关的 CSS 类:

.markdown-body h1 {
  color: #1890ff;
}

Q: 如何处理大文件?

A: 建议后端进行分页或截断,前端可以添加"加载更多"功能。

Q: 支持暗黑模式吗?

A: 当前版本不支持,可以通过 CSS 变量自定义主题色。

Q: PDF 导出图片模糊?

A: 可以调整 imageQuality 参数:

await exportToPdf(element, {
  imageQuality: 1.0  // 最高质量
})

🔗 相关链接