正在造一个的中后台框架轮子 e-admin ,文档与开发同步进行。
文档部分涉及了markdown
解析,刚开始是尝试使用现成库 vue-markdown-loader,但是代码高亮部分不好定制处理,遂放弃。
第一次尝试自已写个loader
,出乎意料的简单。markdown
解析使用的是hyperdown;
代码高亮通过prismjs实现;
代码高亮部分刚开始是尝试用highlight.js但是不知为何JavaScript
第一行的格式化会出现异常,用prismjs则无此问题。
首先安装依赖
npm install hyperdown prismjs -D
创建loader
markdown-loader.js
const HyperDown = require('hyperdown');
const Prism = require('prismjs');
function markdownLoader(val) {
let parser = new HyperDown();
let html = parser.makeHtml(val);
html = html.replace(/(?<=<pre><code[^>]*?>)[\s\S]*?(?=<\/code><\/pre>)/gi, v => {
v = v.replace(/_&/g, ' ').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&');
return Prism.highlight(v, Prism.languages.javascript);
});
return (
`<template><div class="markdown">${html}</div></template>`
);
}
module.exports = markdownLoader;
使用
项目使用的是vue-cli 3.x
,在vue.config.js
添加以下配置
module.exports = {
configureWebpack: config => {
config.module.rules.push({
test: /\.md$/,
use: [
{
loader: 'vue-loader',
},
{
loader: require.resolve('./markdown-loader'),
},
],
},
);
},
};
在入口文件main.js
导入prismjs
样式
import 'prismjs/themes/prism.css';
现在可以把.md
文件当成vue组件来使用了test.md
test.vue
<template>
<test-md></test-md>
</template>
<script>
import testMd from './test.md';
export default {
components: {testMd},
md组件效果
当然也可以作为路由组件来使用,最终实现如下预期效果
扩展 slot
自撸loader
的另一个好处就是自由度高,我们可以随意扩展功能,比如既然md
文件被解析成vue组件,因为文档通常都伴随着实例,如果能在里面md
里面插入slot
在使用中我们随意在插槽中插入实例,那可太方便了,实现起来也就是一个正则的事
function markdownLoader(val) {
let parser = new HyperDown();
let html = parser.makeHtml(val);
html = html.replace(/(?<=<pre><code[^>]*?>)[\s\S]*?(?=<\/code><\/pre>)/gi, v => {
v = v.replace(/_&/g, ' ').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&');
return Prism.highlight(v, Prism.languages.javascript);
});
// 解析slot转换为正常标签
html = html.replace(/<slot[\s\S]*?><\/slot>/gi, v => {
v = v.replace(/_&/g, ' ').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&');
return v;
});
return (
`<template><div class="markdown">${html}</div></template>`
);
}
现在我们可以在md文件里面直接写slot
插槽了test-slot.md
#扩展 slot
###default
这里插入一个默认插槽
<slot></slot>
####footer
这里插入一个具名插槽
<slot name="footer"></slot>
在我们实例中使用这个组件试试效果
<template>
<test-slot>
<el-button type="primary">default</el-button>
<template v-slot:footer>
<el-button type="success">footer</el-button>
</template>
</test-slot>
</template>
<script>
import testSlot from './test-slot.md'
export default {
components: {
testSlot
},
运行 done
添加一个锚点id解析方案
/**
* id解析方案
* markdown ###(#item-1)标题
* html <h3 id="item-1">标题</>
* @type {string}
*/
html = html.replace(/>\(#[\s\S]*?\)/gi, v => {
const id = v.substr(3, v.length - 4);
return ` id="${id}">`;
});
这段代码插入到上面函数的return
之前,就可以把(#item-1)
解析成当前标签的id id = "item-1"
,效果是有的,但是因为这种写法不是markdown
规范,所以慎用吧
以这篇文章的内容为基础搭建的 e-admin中文文档
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。