预计阅读时间: 6分钟
前言
一个好的组件库,其文档必然是易读且易于维护的。 element-ui
作为一个优秀的组件库显然做到了这一点。 element-ui
的官网是使用 vue
开发的,将官方仓库的代码 clone
到本地运行,就可以在本地构建 element-ui
的官网。值得注意的是,根据源码中 vue-router
的路由信息,element-ui
的所有组件文档页引入的并不是一个.vue
文件,而是一个 .md
文件。 打开其中的一个.md
文件( examples/docs/zh-CN/backtop.md
),发现 element-ui
将 markdown
语法和 vue
代码结合到了一起,官网中的组件文档页也是由这些文件生成 ?
## Backtop 回到顶部
返回页面顶部的操作按钮
### 基础用法
滑动页面即可看到右下方的按钮。
:::demo
```html
<template>
Scroll down to see the bottom-right button.
<el-backtop target=".page-component__scroll .el-scrollbar__wrap"></el-backtop>
</template>
```
:::
这种做法节省了大量的维护成本。跟写页面相比,写markdown
显然省事多了。那么 element-ui
是如何做到将一个 .md
文件生成官网中独立的页面呢?
从webpack入手
我们可以在 build/webpack.demo.js
文件中看到 element-ui
的 webpack
配置,在其中我们可以找到 element-ui
对于 .md
文件的处理。
{
test: /\.md$/,
use: [
{
loader: 'vue-loader',
options: {
compilerOptions: {
preserveWhitespace: false
}
}
},
{
loader: path.resolve(__dirname, './md-loader/index.js')
}
]
}
根据这段配置,webpack
一旦遇到以 .md
结尾的文件,就会读取文件中的内容,将这些内容传入相应的 loader
中进行处理。由于 loader
的调用顺序是从下往上的,所以会先调用 md-loader
,然后将 md-loader
处理好的内容传入 vue-loader
中 。只要传入 vue-loader
中的内容符合 vue
的单文件组件的规范,就可以当做一个 vue
文件处理。这样一来,我们就将 .md
文件处理为 vue
文件了。扩展开来,只要我们配置好相应的 loader
,不只是 .md
文件,任意的文件都可以通过 vue-loader
进行处理。
经过以上的分析,我们可以得知,在整个过程中最关键的部分就是 md-loader
了。那么在 md-loader
中, element-ui
是如何做到将 .md
文件处理为 vue
格式的呢?接下来我们可以打开 md-loader
的入口文件一起了解( md-loader/index.js
)。
md-loader地址
md-loader
首先我们需要了解 element-ui
对于 .md
文件的处理思路,主要分为两步:
-
将
.md
文件转换为普通的html
。 -
将转换后的
html
代码处理为vue
格式。
关于第一步有现成的工具可以实现。element-ui
使用的是 markdown-it
。幸运的是这个工具有在线demo,我们可以直接将 markdown
代码复制到其中查看解析结果。在这里我们使用 element-ui
的 button
组件文档作为示例( examples/docs/zh-CN/button.md
)。将该文件复制到在线demo中,即可看到效果。注意右上角的三个标记,分别表示了查看的三种内容:
html
,可以查看markdown
转换后的页面效果。
source
,可以查看markdown
转换后生成的html
代码。
3.debug
,可以查看 markdown
转换后生成的 tokens
数组,后面会用到。
有了 markdown-it
插件的帮助,现在我们已经可以将 .md
文件转换为普通的 html
了。以上的过程如果用代码描述的话就是:
npm i markdown-it
var md = require('markdown-it')();
var result = md.render('button.md中的内容');
没错只有三行 ?
当然,转换后的代码不可能和我们的需求完全一致, element-ui
在转换的过程中也进行了其他的处理。这些配置都放在了 config.js
中。
const md = require('./config');
module.exports = function(source) {
const content = md.render(source);
}
这些配置中主要包括标题锚点和自定义代码块。关于锚点,细心的朋友可以发现,当你将鼠标放在 element-ui
文档的标题上时,会出现一个符号标记,这就是锚点了。
锚点作用是点击之后可以跳转到页面的对应位置。虽然 element-ui
的文档中的标题设置了锚点,但是并没有对应的页面大纲。所以只能通过点击标题触发锚点 ? ( 在 Element Plus
中优化了这个问题 )。
另一个配置是自定义代码块,这是一个很重要的配置。我们可以观察到文档中的有一段内容被 :::demo
标记包裹了起来
::: demo
xxxx
xxxx
:::
很显然这个标记不属于正文里的内容,这里使用了 markdown-it
的一个插件,名叫 markdown-it-container
。这个插件的作用是获取标记内的代码( :::demo )并返回自定义内容。这个过程就类似于 JavaScript
的 replace
方法。
这一段的代码在 build/md-loader/container.js
中。
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>';
}
});
md.use(mdContainer, 'tip');
md.use(mdContainer, 'warning');
};
其中的render
函数返回的 <demo-block>
是 element-ui
中的用于 demo
展示的组件,暂时不用关心。这段代码中最令人费解的部分就是这个 tokens
参数了,这个参数代表的是什么呢?这就要回到我们最开始的在线demo中的 debug
内容了。从中我们可以看到 tokens
是一个数组,里面有一系列的 token
对象,用于描述如何生成 html
标签。token
对象的每一个属性都有各自的意义,如上述代码中的 info
( 代码块中的内容 ),nesting
( 判断标签是否闭合,1
代表标签打开标志,-1
代表标签关闭标志 )。具体可以查看 markdown-it
中文文档,里面还有对 markdown-it
更详尽的介绍。
经过以上的步骤之后,我们终于拿到了一段经过我们转化后的代码了。
这就是 md-loader
的前三行的内容?
const md = require('./config');
module.exports = function(source) {
const content = md.render(source);
}
没错,整篇文章到现在,我们终于讲完了md-loader
入口文件的前三行,大致了解了 content
变量里面的内容了,yeah!
不过别着急,万事开头难。踏出第一步,才会有更多可能。
总结
我们现在已经可以将 .md
文件转换为 html
了。下一篇文章中,我们再一起聊聊如何将转换后的 html
代码处理为 vue
格式。
如果这篇文章对你有所帮助,或者有所启发的话,求关注!求点赞!各位的支持和认可,就是我写作的最大动力?
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!