概述
最近项目组在做一个低代码平台,除了我们平台提供给用户使用的组件之外,需要满足用户也能自定义组件,最后嵌入到项目里面,然后进行使用,平台使用的vue技术栈,这里分享一下实现的原理,有类似需求的可以参考,对于需要远程获取组件相关数据然后动态注册到全局使用的,都可以看看下面的实现思路。
自定义组件流程
首先会提供用户自定义组件的入口,这里就是给用户去编写vue组件,然后编写完成后,保存用户的这个字符串,然后我们就可以在低代码物料区使用我们自定义的这个组件。
保存后,本质上就是保存的这个文件的字符串
其次,我们在低代码构建的脱拽区域可以看到我们定义的自定义组件,现在我们的重点就是将用户写的.vue字符串编译生成组件对象,然后注册到项目里面,我们就可以使用自定义的组件了。
vue-loader
这个库想必大家都不陌生,我们平时写.vue项目最终会经过这个插件的编译生成浏览器能够识别的js代码,但是vue-loader是基于webpack和node环境下使用的,并不能直接在浏览器环境下使用,我们要加载用户写的vue组件代码,本质是个字符串,说白了就是.vue文件里面的内容,需要将其编译组件配置对象,然后注册到项目里面使用,对应浏览器端使用编译器插件也是有的,运行在浏览器环境vue3-sfc-loader和vue2-sfc-loader,具体的介绍可以看git-hub。
具体实现
一个小的demon,本质其实是一样的。
<html>
<body>
<div id="app"></div>
<!-- <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script> -->
<script src="./js/vue2.js"></script>
<!-- <script src="https://unpkg.com/vue@2/dist/vue.runtime.min.js"></script> -->
<script src="./js/vue2-sfc-loader.js"></script>
<script>
async function init() {
const mixinTest = {
mounted() {
console.log("mixinTest");
},
data() {
return {
mixinNumber: 0,
};
},
};
const mainComponent = `
<template>
<div class='wrap'>
<p>这是标题 {{count}}</p>
<div class='container'>this is container</div>
<ul>
<li @click="handleClick(item)" v-for="item in 10" :key="item">{{ item + "----项" }}</li>
</ul>
</div>
</template>
<script>
import mixinTest from "mixinTest"
import myData from "myData"
console.log('myData',myData)
export default {
mixins: [mixinTest],
data(){
return {
count: 0
}
},
mounted() {
console.log("测试组件",this);
},
methods:{
handleClick(item){
console.log('item',item)
this.count++;
}
}
}
<\/script>
<style scoped >
.wrap {
background-color: #000;
color: red;
font-size: 20px;
.container{
width: 200px;
height: 200px;
background-color: red;
color:#000;
&:hover{
color:pink;
}
}
}
<\/style>
`;
const { loadModule, vueVersion } = window["vue2-sfc-loader"];
const options = {
moduleCache: {
vue: Vue,
//自定义传给组件使用import导入使用的值 组件内部可以使用import xxx from "xxx"
mixinTest: mixinTest,
myData: {
vueVersion,
},
},
async getFile(url) {
//这里是接口获取的用户编写的组件字符串
return mainComponent;
},
addStyle(textContent) {
console.log('textContent',textContent)
const style = Object.assign(document.createElement("style"), {
textContent,
});
const ref = document.head.getElementsByTagName("style")[0] || null;
document.head.insertBefore(style, ref);
},
};
let res = await loadModule("/main.vue", options);
//编译生成组件配置项后,注册组件,然后项目里面就可以使用了
Vue.component("test", res);
console.log(res);
const app = new Vue({
el: "#app",
data() {
return {
msg: "Hello Vue 3.0",
};
},
template: `<div>这是根节点 <test></test></div>`,
});
}
init();
</script>
</body>
</html>
总结
最近低代码这块接触的比较多,后续会分享更多关于低代码构建相关的经验。