基于VitePress创建组件文档

我们准备用vitepress做我们的组件文档,方便我们浏览组件,提供使用指南给用户。

安装VitePress

安装:

yarn add -D vitepress

创建第一个文档:

mkdir docs && echo '# Hello VitePress' > docs/index.md

增加脚本命令:

{
  "scripts": {
    "docs:dev": "vitepress dev docs",
    "docs:build": "vitepress build docs",
    "docs:serve": "vitepress serve docs"
  }
}

本地启动:

yarn docs:dev

浏览器访问看效果:http://localhost:3000/,这是VitePress默认的效果。

在这里插入图片描述

参考:https://vitepress.vuejs.org/guide/getting-started.html

配置VitePress

我们需要实现以下功能:

  • 需要一个左侧菜单,用来展示我们有哪些组件
  • 点击左侧菜单中的组件,可以展示这个组件的基本信息、Demo、API文档

配置sidebar

VitePress有一个配置文件,里面有一个themeConfig/sidebar配置,可以配置左侧菜单。

docs/.vitepress/config.ts

const sidebar = [
  {
    text: '快速开始',
    items: [
      { text: '安装', link: '/guide/install' } // /guide/install.md
    ]
  },
  {
    text: '通用',
    items: [
      { text: 'Button 按钮', link: '/components/button/' } // /components/button/index.md
    ]
  },
  { text: '导航', items: [] },
  { text: '反馈', items: [] },
  { text: '数据录入', items: [] },
  { text: '数据展示', items: [] },
  { text: '布局', items: [] }
]

export default {
  themeConfig: {
    sidebar
  }
}

点击左侧菜单的Button,看下效果,页面404了:

在这里插入图片描述

创建Button组件的文档

404的原因是我们没有创建相应的文档,创建docs/component/button/index.md

先随便写一些内容:

# Button 按钮

再看下效果:

在这里插入图片描述

在md中增加vue组件

VitePress的一大好处是可以直接在md中写vue组件,VitePress会将其渲染出来,docs/components/button/index.md

# Button 按钮
<s-button></s-button>

我们还没有实现这个s-button,所以没有效果。

编写一个Button组件

下面我们编写这个Button组件,sheep-ui/src/button/src/Button.tsx:

const Button = () => <div>Button 按钮</div>
export default Button

引入Button组件

docs/.vitepress/theme/index.ts

import DefaultTheme from 'vitepress/theme'
import Button from '../../../src/button/src/Button'

export default {
  ...DefaultTheme,
  enhanceApp({ app }) {
    // register global components
    app.component('s-button', Button)
  }
}

报错:React is not defined

Uncaught (in promise) ReferenceError: React is not defined
    at Button (button.tsx:1)

引入jsx插件

docs/vite.config.ts中引入jsx插件:

import { defineConfig } from 'vite'
import vueJsx from '@vitejs/plugin-vue-jsx'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vueJsx()]
})

组件显示出来了!

在这里插入图片描述

组件Demo代码展示

使用 Vitepress 编写组件示例有以下不足之处:

  • 1.组件示例和示例代码本质上一样,却需要写两遍。
  • 2.Vitepress 无法渲染 Markdown 中的 script 和 style 代码块。

比如下面这样:

<!-- index.md -->

<!-- 以下是显示组件部分 -->
<s-icon name="emoji"><s-icon>

<!-- 以下是暴露到文档的代码块 -->
<!-- 需要再次重复写同样的代码 -->
```html
<s-icon name="emoji"><s-icon>

vitepress有款支持demo展示的插件vitepress-theme-demoblock可以解决以上问题,写一遍同时显示结果和代码块,先安装:

yarn add -D vitepress-theme-demoblock

注入插件

首先我们得知道vitepress关于markdown的拓展规则,vitepress 使用markdown-it作为 markdown 渲染器,具体可以查看,我们得将插件在vitepressconfig.js中注册,如下面这样:

import { demoBlockPlugin } from 'vitepress-theme-demoblock'

module.exports = {
  markdown: {
    config: (md) => {
      // 这里可以使用 markdown-it 插件,vitepress-theme-demoblock就是基于此开发的
      md.use(demoBlockPlugin)
    }
  }
}

我们还得在docs/.vitepress/theme/index.ts中注册vitepress-theme-demoblock插件所需的demodemo-block组件,以及所需样式。如下面这样

// 主题样式
import 'vitepress-theme-demoblock/theme/styles/index.css'
// 插件的组件,主要是demo组件
import Demo from 'vitepress-theme-demoblock/components/Demo.vue'
import DemoBlock from 'vitepress-theme-demoblock/components/DemoBlock.vue'

export default {
  enhanceApp({ app }) {
    app.component('Demo', Demo)
    app.component('DemoBlock', DemoBlock)
  }
}

至此,vitepress-theme-demoblock的就在vitepress中注册成功了!

接下来按要求编写文档,比如下面这样写:

:::demo 使用`s-button`创建一个按钮。
  ```vue
  <template>
    <s-button></s-button>
  </template>

:::
最终生成的效果如图所示,效果非常棒~
在这里插入图片描述

样式不太协调,而且不支持暗黑模式,这里给个样式仅供参考

```Sass (Sass) 
$dividing-line: #dfe1e6;
$dividing-line-dark: #3b3b3b;
$base-bg: #ffffff;
$base-bg-dark: #2c2c2c;
$brand: #42b883;
$area: #f8f8f8;
$area-dark: #242424;
$text:#252b3a;
$text-dark:#f8f8f8;
$font-size: 12px;
$disabled-line: #dfe1e6;
$border-radius: 3px;
$disabled-bg:#f5f5f6;
$disabled-text:#adb0b8;

// 点击复制代码 message样式修复
.demoblock-message-wrap{
  .demoblock-message-content{
    background-color: #3dcca6 !important;
  }
}

.dark {
  .demo-block {
    border: solid 1px $dividing-line-dark !important;
  }
  .demo-block-control {
    background-color: $base-bg-dark !important;
    border-top: solid 1px $dividing-line-dark !important;
  
    &:hover {
      color: $brand !important;
    }
  
    .control-button {
      color: $brand !important;
    }

    .control-icon {
      color: #565656
    }
  }
  .meta {
    border-top: solid 1px $dividing-line-dark !important;
    background-color: $area-dark !important;
  
    .description {
      border:transparent !important;
      color: $text-dark !important;
      background-color: transparent !important;
    }

    .highlight div[class*='language-'] {
      margin: 0 !important;
      border-radius: 0;
      border: solid 1px $dividing-line-dark !important;
      background-color: $base-bg-dark !important;
    }
  }

  .vp-doc [class*='language-'] {
    pre {
      background-color: $base-bg-dark !important;
      
      code{
        background-color: $base-bg-dark !important;
        border-radius: 10;
        color: $text-dark !important
      }
    }
  }
}

.demo-block {
  border: solid 1px $dividing-line !important;

  &.hover {
    box-shadow: none !important;
  }

  .source {
    .demo-spacing {
      & > * {
        margin: 0 8px 8px 0;

        &:last-child {
          margin-right: 0;
        }
      }

      &:last-child {
        & > * {
          margin-bottom: 0;
        }
      }
    }
  }
}

.demo-block-control {
  background-color: $base-bg !important;
  border-top: solid 1px $dividing-line !important;

  &:hover {
    color: $brand !important;
  }

  .control-button {
    color: $brand !important;
  }
}

.meta {
  border-top: solid 1px $dividing-line !important;
  background-color: $area !important;

  .description {
    border: solid 1px $dividing-line !important;
    color: $text !important;
    background-color: $base-bg !important;
  }
}

[class^=version-tag] {
  display: inline-block;
  padding: 0 4px;
  line-height: 20px;
  color: #ffffff;
  border-radius: 4px;
}

.version-tag-1 {
  background-color: #3dcca6;
}

.version-tag-2 {
  background-color: #f66f6a;
}



// 代码样式
code {
  margin: 0;
  border-radius: 3px;
  padding: 0.25rem 0.5rem;
  font-family: var(--code-font-family);
  font-size: 0.85em;
  color: var(--text,#252b3a) !important;
  background-color: $area !important;
}

code .token.deleted {
  color: #ec5975;
}

code .token.inserted {
  color: var(--c-brand);
}

div[class*='language-'] {
  position: relative;
  margin: 1rem -1.5rem;
  background-color: $area !important;
  overflow-x: auto;
}

li > div[class*='language-'] {
  border-radius: 6px 0 0 6px;
  margin: 1rem -1.5rem 1rem -1.25rem;
}

@media (min-width: 420px) {
  div[class*='language-'] {
    margin: 1rem 0;
    border-radius: 6px;
  }

  li > div[class*='language-'] {
    margin: 1rem 0 1rem 0rem;
    border-radius: 6px;
  }
}

[class*='language-'] pre,
[class*='language-'] code {
  text-align: left;
  white-space: pre;
  word-spacing: normal;
  word-break: normal;
  word-wrap: normal;
  -moz-tab-size: 4;
  -o-tab-size: 4;
  tab-size: 4;
  -webkit-hyphens: none;
  -moz-hyphens: none;
  -ms-hyphens: none;
  hyphens: none;
}

[class*='language-'] pre {
  position: relative;
  z-index: 1;
  margin: 0;
  padding: 1.25rem 1.5rem;
  background: transparent;
  overflow-x: auto;
}

[class*='language-'] code {
  padding: 0;
  line-height: var(--code-line-height);
  font-size: var(--code-font-size);
  color: #eee;
}

/* Line highlighting */

.highlight-lines {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  padding: 1.25rem 0;
  width: 100%;
  line-height: var(--code-line-height);
  font-family: var(--code-font-family);
  font-size: var(--code-font-size);
  user-select: none;
  overflow: hidden;
}

.highlight-lines .highlighted {
  background-color: rgba(0, 0, 0, 0.66);
}

/* Line numbers mode */

div[class*='language-'].line-numbers-mode {
  padding-left: 3.5rem;
}

.line-numbers-wrapper {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  z-index: 3;
  border-right: 1px solid rgba(0, 0, 0, 0.5);
  padding: 1.25rem 0;
  width: 3.5rem;
  text-align: center;
  line-height: var(--code-line-height);
  font-family: var(--code-font-family);
  font-size: var(--code-font-size);
  color: #888;
}

/* Language marker */

div[class*='language-']:before {
  position: absolute;
  top: 0.6em;
  right: 1em;
  z-index: 2;
  font-size: 0.8rem;
  color: #888;
}

div[class~='language-html']:before,
div[class~='language-markup']:before {
  content: 'html';
}

div[class~='language-md']:before,
div[class~='language-markdown']:before {
  content: 'md';
}

div[class~='language-css']:before {
  content: 'css';
}

div[class~='language-sass']:before {
  content: 'sass';
}

div[class~='language-scss']:before {
  content: 'scss';
}

div[class~='language-less']:before {
  content: 'less';
}

div[class~='language-stylus']:before {
  content: 'styl';
}

div[class~='language-js']:before,
div[class~='language-javascript']:before {
  content: 'js';
}

div[class~='language-ts']:before,
div[class~='language-typescript']:before {
  content: 'ts';
}

div[class~='language-json']:before {
  content: 'json';
}

div[class~='language-rb']:before,
div[class~='language-ruby']:before {
  content: 'rb';
}

div[class~='language-py']:before,
div[class~='language-python']:before {
  content: 'py';
}

div[class~='language-sh']:before,
div[class~='language-bash']:before {
  content: 'sh';
}

div[class~='language-php']:before {
  content: 'php';
}

div[class~='language-go']:before {
  content: 'go';
}

div[class~='language-rust']:before {
  content: 'rust';
}

div[class~='language-java']:before {
  content: 'java';
}

div[class~='language-c']:before {
  content: 'c';
}

div[class~='language-yaml']:before {
  content: 'yaml';
}

div[class~='language-dockerfile']:before {
  content: 'dockerfile';
}

div[class~='language-vue']:before {
  content: 'vue';
}

/**
 * prism.js tomorrow night eighties for JavaScript, CoffeeScript, CSS and HTML.
 * Based on https://github.com/chriskempson/tomorrow-theme
 *
 * @author Rose Pritchard
 */
.token.comment,
.token.block-comment,
.token.prolog,
.token.doctype,
.token.cdata {
  color: #999;
}

.token.punctuation {
  color: #ccc;
}

.token.tag,
.token.attr-name,
.token.namespace,
.token.deleted {
  color: #e2777a;
}

.token.function-name {
  color: #6196cc;
}

.token.boolean,
.token.number,
.token.function {
  color: #f08d49;
}

.token.property,
.token.class-name,
.token.constant,
.token.symbol {
  color: #f8c555;
}

.token.selector,
.token.important,
.token.atrule,
.token.keyword,
.token.builtin {
  color: #cc99cd;
}

.token.string,
.token.char,
.token.attr-value,
.token.regex,
.token.variable {
  color: #7ec699;
}

.token.operator,
.token.entity,
.token.url {
  color: #67cdcc;
}

.token.important,
.token.bold {
  font-weight: bold;
}

.token.italic {
  font-style: italic;
}

.token.entity {
  cursor: help;
}

.token.inserted {
  color: green;
}


还需要在.vitepress/theme/index.ts中引入样式文件

import './demo-block.scss'

由于用到sass,还需要安装一下它:

yarn add -D sass

最后,需要大家注意的是,当我们需要在demo代码块中编写js或ts代码时,引入库一定要使用单引号,否则会爆下图的错误,这是vitepress-theme-demoblock的特殊邀请,详情查阅其文档。

  :::demo 导入vue的时候使用单引号,使用单引号,使用单引号
  <script setup>
    import { ref } from 'vue';
    // import { ref } from "vue"; // 这样引入会报错
    const title = ref('card')
  </script>
  :::
  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林多多@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值