前言
需求如下 在写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> |