前言
需求如下 在写xinyi-ui 官网时,需要对组件进行文档说明,说明文档都是md格式的文件,能否直接将md文件显示到页面上,而不改为html 呢?
现在有 install.md 和 get-started.md 两个文件
第一步 实现一个vite插件 md => html
1 | var MarkdownIt = require('markdown-it') |
2 | const marked = new MarkdownIt() |
3 | |
4 | const mdToJs = str => { |
5 | const content = JSON.stringify(marked.render(str)) |
6 | return `export default ${content}` |
7 | } |
8 | |
9 | export function md() { |
10 | return { |
11 | name: 'md', |
12 | transform(src,url){ |
13 | if(url.endsWith('.md')){ |
14 | return { |
15 | code: mdToJs(src), |
16 | map: null // 如果可行将提供 source map |
17 | } |
18 | } |
19 | } |
20 | } |
21 | } |
第二步创建组件模板 Markdown.vue
因为只是md文件不同,可以使用同一个组件模板,通过文件路径显示不同的html内容
1 | <template> |
2 | <article v-html="content"></article> |
3 | </template> |
那么如何获取这个content 呢?
只要引入md 文件 vite插件就会自动将md文件转为html 字符串
1 | //router.js |
2 | // 通过渲染函数将 path 传递给 markdown.vue 在markdown.vue 中引入md文件 |
3 | const md = (filename:string) => h(Markdown, { path: `../markdown/${filename}.md`, key: filename }) |
4 | const routes = { |
5 | // component 可以使VNode |
6 | { path: 'install', component: md('install')}, |
7 | { path: 'get-started', component: md('get-started') }, |
8 | } |
但是我们不能再setup 中使用 import xxx from ...
的语法,可以使用异步引入的方式
1 | // Markdown.vue |
2 | export default { |
3 | props: { |
4 | path: { |
5 | type: String, |
6 | required: true, |
7 | }, |
8 | }, |
9 | setup(props:any) { |
10 | const content = ref<string>(''); |
11 | import(/* @vite-ignore */props.path).then((result) => { |
12 | content.value = result.default; // 这里可以获取到 |
13 | }); |
14 | return { |
15 | content, |
16 | }; |
17 | }, |
18 | }; |
显示在页面 并添加样式
- 安装 github-markdown-css
- 在main.ts 或 MarkDown.vue中引入 css
- 在article上添加class markdown-body
- v-html 显示 html
1 | <article class="markdown-body" v-html="content"></article> |
将动态引入改为静态引入
build后发现在生产环境会报错 是因为rollup打包不接受这种拼接字符串的模式
所以将动态引入文件 改为静态引入
这样也将异步引入改为了同步引入了
1 | // main.ts |
2 | import install from '../markdown/install.md' |
3 | import getStarted from '../markdown/get-started.md' |
4 | |
5 | // 直接将content 传给Markdown.vue |
6 | const md = (content:string) => h(Markdown, { content }) |
7 | const routes = { |
8 | { path: 'install', component: md(install)}, |
9 | { path: 'get-started', component: md(getStarted) }, |
10 | } |
这样直接引入 ts 会报错 可以加 // @ts-ignore
不管
也可以在markdown中添加一个声明文件 markdown.d.ts
1 | declare module "*.md" { |
2 | const content: string; |
3 | export default content; |
4 | } |
这样打开就不会报错啦
Markdown.vue
中显示markdown
1 | <template> |
2 | <!--content 就是 html 格式的字符串--> |
3 | <article class="markdown-body" v-html="content"></article> |
4 | </template> |
5 | |
6 | <script lang="ts"> |
7 | import { ref } from "vue"; |
8 | export default { |
9 | props: { |
10 | content: { |
11 | type: String, |
12 | required: true, |
13 | }, |
14 | } |
15 | }; |
16 | </script> |