.md文件在页面上功能展示以及代码展示
.md文件在页面上功能展示以及代码展示简单来说就是:一个.md文件既展示页面又展示代码逻辑:相关技术:markdown-it 渲染 markdown 基本语法,转化为htmlmarkdown-it-anchor 为各级标题添加锚点markdown-it-container 用于创建自定义的块级容器vue-markdown-loader 核心loader过程:配置markdow...
·
.md文件在页面上功能展示以及代码展示
简单来说就是:一个.md文件既展示页面又展示代码
逻辑:
相关技术:
markdown-it 渲染 markdown 基本语法,转化为html
markdown-it-anchor 为各级标题添加锚点
markdown-it-container 用于创建自定义的块级容器
vue-markdown-loader 核心loader
过程:
- 配置markdown-it
markdown-it-anchor添加锚点
并导出相应的变量md
const Config = require('markdown-it-chain');
const anchorPlugin = require('markdown-it-anchor');
const slugify = require('transliteration').slugify;
const containers = require('./containers');
const overWriteFenceRule = require('./fence');
const config = new Config();
config
.options.html(true).end()
.plugin('anchor').use(anchorPlugin, [
{
level: 2,
slugify: slugify,
permalink: true,
permalinkBefore: true
}
]).end()
.plugin('containers').use(containers).end();
const md = config.toMd();
overWriteFenceRule(md);
module.exports = md;
- 用markdown-it解析.md里面的数据
抽离template和script,通过插件编译成render Functioon,利用他创建组件。
const content = md.render(source);
const commentContent = content.slice(commentStart + startTagLen, commentEnd);
const html = stripTemplate(commentContent);
const script = stripScript(commentContent);
let demoComponentContent = genInlineComponentText(html, script);
const demoComponentName = `element-demo${id}`;
- 对.md中的:::demo进行解析
const mdContainer = require('markdown-it-container');
module.exports = md => {
md.use(mdContainer, 'demo', {
validate(params) {
return params.trim().match(/^demo\s*(.*)$/);
},
render(tokens, idx) {
const m = tokens[idx].info.trim().match(/^demo\s*(.*)$/);
if (tokens[idx].nesting === 1) {
const description = m && m.length > 1 ? m[1] : '';
const content = tokens[idx + 1].type === 'fence' ? tokens[idx + 1].content : '';
return `<demo-block>
${description ? `<div>${md.render(description)}</div>` : ''}
<!--element-demo: ${content}:element-demo-->
`;
}
return '</demo-block>';
}
})
};
- 根据标记找到并拼装组件
module.exports = function(source) {
const content = md.render(source);
const startTag = '<!--element-demo:';
const startTagLen = startTag.length;
const endTag = ':element-demo-->';
const endTagLen = endTag.length;
let componenetsString = '';
let id = 0; // demo 的 id
let output = []; // 输出的内容
let start = 0; // 字符串开始位置
let commentStart = content.indexOf(startTag);
let commentEnd = content.indexOf(endTag, commentStart + startTagLen);
while (commentStart !== -1 && commentEnd !== -1) {
output.push(content.slice(start, commentStart));
const commentContent = content.slice(commentStart + startTagLen, commentEnd);
const html = stripTemplate(commentContent);
const script = stripScript(commentContent);
let demoComponentContent = genInlineComponentText(html, script);
const demoComponentName = `element-demo${id}`;
output.push(`<template slot="source"><${demoComponentName} /></template>`);
componenetsString += `${JSON.stringify(demoComponentName)}: ${demoComponentContent},`;
// 重新计算下一次的位置
id++;
start = commentEnd + endTagLen;
commentStart = content.indexOf(startTag, start);
commentEnd = content.indexOf(endTag, commentStart + startTagLen);
}
// 仅允许在 demo 不存在时,才可以在 Markdown 中写 script 标签
// todo: 优化这段逻辑
let pageScript = '';
if (componenetsString) {
pageScript = `<script>
export default {
name: 'component-doc',
components: {
${componenetsString}
}
}
</script>`;
} else if (content.indexOf('<script>') === 0) { // 硬编码,有待改善
start = content.indexOf('</script>') + '</script>'.length;
pageScript = content.slice(0, start);
}
output.push(content.slice(start));
return `
<template>
<section class="content element-doc">
${output.join('')}
</section>
</template>
${pageScript}
`;
};
简单介绍:
content结构类似:
let content = `
Description1 //description
Component1 // 展示组件
componentCode1//展示代码
Description2
Component2
componentCode2
`
output的过程:
1·第一次循环
output.push(Description1)
output.push(Component1)
2.第二次循环
output.push(componentCode1)
output.push(Description2)
output.push(Component2)
3.最后 output.push(content.slice(start))
最终在script的代码就是
script = `<script>
export default {
name: 'component-doc',
components: {
component1:(function() {*render1* })(),
component2:(function() {*render2* })(),
component3:(function() {*render3* })(),
}
}
</script>`;
最后返回:
return `
<template>
<section class="content element-doc">
${output.join('')}
</section>
</template>
${script}
`;
得到
<h3>我是demo1</h3>
<template slot="source"><demo1/></template>
<template slot="highlight"><pre v-pre><code class="html">${md.utils.escapeHtml(content)}</code></pre></template>
- 锚点跳转函数
renderAnchorHref() {
if (/changelog/g.test(location.href)) return;
const anchors = document.querySelectorAll('h2 a,h3 a,h4 a,h5 a');
const basePath = location.href.split('#').splice(0, 2).join('#');
[].slice.call(anchors).forEach(a => {
const href = a.getAttribute('href');
a.href = basePath + href;
});
},
参考:element源码
Element的markdown-loader源码解析
Element源码系列——Vue加载Markdown格式组件上篇
更多推荐
已为社区贡献2条内容
所有评论(0)