如何简单实现一个低代码平台

1,438 阅读6分钟

前言

最近不是低代码一度非常的火热,通过拖拖拽拽就可以很快速的生成一个页面,还能够支持自定义的去修改一些细节的参数,然后一件就可以生成一个网页,大大提升了开发的效率。

但是其实低代码的原理并不是非常的复杂,大部分功能都是有现有的第三方库,主要的难点是在于整个低代码平台的一个数据设计以及整体架构。

项目整体流程

对于常见的低代码平台,一般是分为物料区,内容区和编辑区,主要的作用就是将物料区的组件拖动到中间的内容区,并且在编辑区可以编辑选择的内容块的属性,这就是一个最简单的可视化搭建平台。

那么先对整体的一个布局有一个大概的了解

image.png

Vue 拖拽插件之 vuedraggable

我写的低代码平台暂时是基于 Vue2 来实现的,所以也用到了 Vue 的一个拖拽第三方库 -- vuedraggable ,这个拖拽库整体的功能十分强大,并且网上现在有中文的使用文档- vue.draggable中文文档 - itxst.com,感兴趣的话可以深入学习一下里面实现的逻辑,本文就不做太多的描述。

利用导入的 draggable 这个标签,我们就可以在这个标签当中定义拖拽的内容,利用内部提供给我们的一些属性来对拖拽做出自定义,比方说:

  • chosenClass: 被选中的元素会被添加上的类名。
  • group: 组名,相同的组名之间可以互相拖拽,有两种传入的格式,跟详细的可以看文档。
  • animation: 顾名思义,过渡动画的时间。
  • @start: 拖拽开始触发的函数
  • @end:拖拽结束触发的函数
<template>
  <div>
    <div>{{ drag ? "拖拽中" : "拖拽停止" }}</div>
    <!--使用draggable组件-->
    <draggable
      v-model="myArray"
      chosenClass="chosen"
      forceFallback="true"
      group="people"
      animation="1000"
      @start="onStart"
      @end="onEnd"
    >
      <transition-group>
        <div class="item" v-for="element in myArray" :key="element.id">
          {{ element.name }}
        </div>
      </transition-group>
    </draggable>
  </div>
</template>
<style scoped>
/*被拖拽对象的样式*/
.item {
  padding: 6px;
  background-color: #fdfdfd;
  border: solid 1px #eee;
  margin-bottom: 10px;
  cursor: move;
}
/*选中样式*/
.chosen {
  border: solid 2px #3089dc !important;
}
</style>
<script>
//导入draggable组件
import draggable from "vuedraggable";
export default {
  //注册draggable组件
  components: {
    draggable,
  },
  data() {
    return {
      drag: false,
      //定义要被拖拽对象的数组
      myArray: [
        { people: "cn", id: 1, name: "www.itxst.com" },
        { people: "cn", id: 2, name: "www.baidu.com" },
        { people: "cn", id: 3, name: "www.taobao.com" },
        { people: "us", id: 4, name: "www.google.com" },
      ],
    };
  },
  methods: {
    //开始拖拽事件
    onStart() {
      console.log(this.myArray);
      this.drag = true;
    },
    //拖拽结束事件
    onEnd() {
      console.log(this.myArray);
      this.drag = false;
    },
  },
};
</script>

1657421506578.gif

并且通过在拖拽开始和拖拽结束的事件中打印出我们用于渲染的数组 myArray 就能够发现,其实拖拽的本质就是数据变化,在拖拽结束的时候会帮我们去更改渲染用的数据,从而生成新的视图。

image.png

并且通过稍加改造,用两个相同的 group 来定义 draggable 标签,我们就能够实现在两个区域之间的元素拖拽了。

1657422760735.gif

这样是不是就能够为后面低代码平台物料区和内容区之间的交互打下了基础,我们所需要做的就是在两个不同的区域用不同的方式去处理这些数据

13292777953549378.gif

定义数据模型

在上面我们说到了,其实物料和内容的本质就是一堆数据,区别在于,放在物料区和内容区我们会用不同的组件去渲染它们,比方说放在物料区,可能就只需要一张图片,一个标题就能够渲染出物料区的图标,但是当我们把物料拖动到内容区的时候,数据就会移动到内容区这个数组当中,那么我们就需要用一个字段来辨别,当前的这个数据是哪个类型的内容组件,一般我们都是直接用这个组件的名称来做一个区分。

在这里就需要提到 Vue 提供的一个 component 标签,一般来说,我们在 Vue 中渲染不同的组件都是通过 v-ifv-else 之类的指令组合起来判断渲染不同组件,但是使用 component 标签,这个标签接收一个 is 属性,属性代表的就是你需要渲染的组件,并且可以通过 v-bind 来将数据传入这个组件,这样我们就能够实现组件的动态渲染,而不是通过 v-ifv-else 去判断渲染怎么组件。

API — Vue.js (vuejs.org)

那么在这之后,我们就能够得到最开始的数据模型,首先对于一个空间来说,它是一个对象,这个对象中有一张图片,一个标题,以及一个组件名称,这里需要注意,因为我们是使用 component 标签进行渲染,所以数据里面的组件名称需要和实际挂在的组件名相同,这样 Vue 才能帮我们去找到并且渲染这个组件。

剩下的就是和组件相关的属性,比方说你是一个图片控件,那么图片的地址就需要成为一个属性传入进去,一开始可能为空,但是后面可以支持修改。又或者一个标题空间,那么标题就也是这个控件的一个属性,我们也需要先定义出来。

定义图片控件

那么我们用图片控件来做一个例子,首先对于一个控件来说,就是一个文件夹,底下存放着他的渲染组件,以及定义它属性的json文件

image.png

当然这里这样定义并不是一定的,只是看个人的写法不同。

那么首先,我们在加载的时候,就可以去获取到这个文件内的内容,将 nameicon 用于渲染物料区的图标和名称,然后 fields 底下定义的数据就是控件可以提供给配置的属性。

有人会发现,不是还需要一个组件名称吗,但是在这个json文件中并没有看到组件的名称,因为我们在注册这个组件的时候可以通过 Vue.component() 这个方法来进行注册

API (Vue-component) — Vue.js (vuejs.org)

这函数第一个参数传入一个组件名称,第二个参数传入一个 Vue 组件,这样我们就能够自定义想要的组件名字了。

webpack 之 require.context()

上面我们说到了可以通过 Vue.component() 来动态注册,但是问题是,注册的这些数据要从哪里来呢,这时候就可以用到一个 webpack 提供给我们的方法 require.context()

  • require.context(directory,useSubdirectories,regExp)

    • directory:表示检索的目录
    • useSubdirectories:表示是否检索子文件夹
    • regExp:匹配文件的正则表达式,一般是文件名 例如 require.context("@/views/components",false,/.vue$/)

利用这个方法,我们就能够拿到所有组件的 json 文件以及对应组件 index.vue 实例了,然后在通过 Vue.component() 进行动态注册。

像我的内容控件都是放在 custom-components 这个目录下,那么就可以像下面这样进行动态注册

import Vue from "vue";

register(require.context("@/custom-components", true, /.vue/));

/**
 * 注册对应包下所有组件
 * @param {*} path 包路径
 */
function register(context) {
  context.keys().forEach((cnt) => {
    const component = context(cnt);
    let ctrl = component.default || component;
    let a = ctrl.name;
    let b = ctrl;

    // 注册组件
    Vue.component(a, b);
  });
}

那么到此为止,我们就能够实现简单的讲 icon 从左侧拖动到中间区域并且实现渲染,在这之后,我们会再来讲讲右侧的编辑区应该如何设计,以及要怎么做到右侧右侧编辑就能够改变中间的渲染。

参考资料

vuedraggable - npm

Mall-Cook: 介绍 Mall-Cook是一个基于 vue 开发的可视化商城搭建平台,包括多页面可视化构建、Json Schema生成器(可视化搭建物料控制面板),实现组件流水线式标准接入平台 (gitee.com)

require.context()的用法详解