我们准备用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
默认的效果。
配置VitePress
我们需要实现以下功能:
- 需要一个左侧菜单,用来展示我们有哪些组件
- 点击左侧菜单中的组件,可以展示这个组件的基本信息、Demo、API文档
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 渲染器,具体可以查看,我们得将插件在vitepress
的config.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
插件所需的demo
和demo-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>
:::
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/79690.html