低代码平台实践之用户自定义物料组件

837 阅读3分钟

概述

最近项目组在做一个低代码平台,除了我们平台提供给用户使用的组件之外,需要满足用户也能自定义组件,最后嵌入到项目里面,然后进行使用,平台使用的vue技术栈,这里分享一下实现的原理,有类似需求的可以参考,对于需要远程获取组件相关数据然后动态注册到全局使用的,都可以看看下面的实现思路。

自定义组件流程

首先会提供用户自定义组件的入口,这里就是给用户去编写vue组件,然后编写完成后,保存用户的这个字符串,然后我们就可以在低代码物料区使用我们自定义的这个组件。

image.png 保存后,本质上就是保存的这个文件的字符串 image.png

其次,我们在低代码构建的脱拽区域可以看到我们定义的自定义组件,现在我们的重点就是将用户写的.vue字符串编译生成组件对象,然后注册到项目里面,我们就可以使用自定义的组件了。

image.png

vue-loader

这个库想必大家都不陌生,我们平时写.vue项目最终会经过这个插件的编译生成浏览器能够识别的js代码,但是vue-loader是基于webpack和node环境下使用的,并不能直接在浏览器环境下使用,我们要加载用户写的vue组件代码,本质是个字符串,说白了就是.vue文件里面的内容,需要将其编译组件配置对象,然后注册到项目里面使用,对应浏览器端使用编译器插件也是有的,运行在浏览器环境vue3-sfc-loadervue2-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>

总结

最近低代码这块接触的比较多,后续会分享更多关于低代码构建相关的经验。