目录
自定义loader,功能:获取当前组件文件源代码以及指定代码块
定义组件BasicDemoBlock,功能:渲染组件|展示源码|展示说明
使用BasicDemoBlock组件进行组件渲染以及源码渲染
设计目标
1.可以渲染组件
2.可以展示组件源代码
3.可以展示组件的说明文案
设计思路
1.设计一个组件,接受参数为组件实例对象。
2.渲染方案使用<component is="myComponent" />
3.源代码方案使用自定义loader,通过获取文件源码赋值给自定义属性。
4.说明文案同3
实例说明
目标:需要在@/views/Table/index.vue中渲染出./demos/下的所有子组件。
给子组件增加docs代码块
<docs>
<source-title>简单表格</source-title>
<source-desc>支持分页展示的简单表格示例</source-desc>
</docs>
自定义loader,功能:获取当前组件文件源代码以及指定代码块
const fs = require('fs');
const { baseParse } = require('@vue/compiler-core');
module.exports = function (source, map) {
// 1. 获取带有 <docs /> 标签的文件完整路径
const { resourcePath } = this
// 2. 读取文件内容
const file = fs.readFileSync(resourcePath).toString()
// 3. 通过 baseParse 将字符串模板转换成 AST 抽象语法树
// 3.1获取源代码信息标签内容
const sourceInfoTag = baseParse(file).children.find(n => {
return n.tag === 'docs'
})
const sourceTitleTag = sourceInfoTag.children.find(n => n.tag === 'source-title')
const sourceDescTag = sourceInfoTag.children.find(n => n.tag === 'source-desc')
// // 4. 标题
const title = (sourceTitleTag.children[0]||{}).content
// // 4.1描述
const desc = (sourceDescTag.children[0] || {}).content
// 5. 将 <source-info></source-info> 标签和内容抽离
const main = file.split(sourceInfoTag.loc.source).join('').trim()
// Component.options.__sourceCodeTitle = ${JSON.stringify(title)}
// Component.options.__sourceCodeTitle = ${JSON.stringify(desc)}
// 6. 回到并添加到 组件对象上面
this.callback(
null,
`export default function (Component) {
Component.options.__sourceCode = ${JSON.stringify(main)}
Component.options.__sourceCodeTitle = ${JSON.stringify(title)}
Component.options.__sourceCodeDesc = ${JSON.stringify(desc)}
}`,
map
)
}
使用自定义loader
定义组件BasicDemoBlock,功能:渲染组件|展示源码|展示说明
<template>
<el-card class="basic-demo-block">
<div slot="header" class="clearfix">
<div class="block__title" style="text-align:left;font-weight:bolder;">
<slot name="title">
{{ component.__sourceCodeTitle }}
</slot>
</div>
<div class="block__desc" style="text-align:left;color:#999;font-size:12px;">
<slot name="desc">
{{ component.__sourceCodeDesc }}
</slot>
</div>
</div>
<div class="block__content">
<div class="content--component">
<slot>
<component :is="component" :key="component.__sourceCodeTitle" />
</slot>
</div>
<div class="content__sourcecode">
<el-collapse>
<el-collapse-item title="查看源代码" name="1">
<!-- 代码高亮方案 使用Prism -->
<pre class="language-css" v-html="renderHtml"></pre>
</el-collapse-item>
</el-collapse>
</div>
</div>
</el-card>
</template>
<script>
import Prism from "prismjs";
import "prismjs/themes/prism-okaidia.css";
export default {
name: "BasicDemoBlock",
props: {
component: {
type: Object,
required: true,
},
},
data() {
return {};
},
computed: {
renderHtml: function () {
return Prism.highlight(
this.component.__sourceCode,
Prism.languages.html,
"html"
);
},
},
};
</script>
<style>
</style>
在index.vue批量引入demos目录下的所有组件
使用BasicDemoBlock组件进行组件渲染以及源码渲染
<template>
<article>
<section
v-for="(key, index) in modules"
:key="index"
style="margin: 50px 20px"
>
<BasicDemoBlock :component="key"> </BasicDemoBlock>
</section>
</article>
</template>
<script>
import BasicDemoBlock from "@/components/BasicDemoBlock";
const files = require.context("@/views/Table/demos", false, /\.vue$/);
const modules = {};
files.keys().forEach((key) => {
const name = key.match(/\.\/(.+?)\./)[1];
modules[name] = files(key).default || files(key);
});
export default {
components: { BasicDemoBlock },
data() {
return {
modules: modules,
};
},
};
</script>
<style></style>
-
最终结果展示