低代码平台

1 介绍

1.1 背景

近些年来,随着Saas行业的高速发展,低代码的概念也逐渐流行了起来,而低代码产品也越来越多地出现在我们的身边,像国外的Mendix,国内的宜搭、苍穹、简道云等等。基于低代码应用构建平台,通过图形化的拖拉拽配置界面,并兼容了自定义的组件、代码扩展,在B端后台管理类网站建设中很大程度上提升了效率。

1.2 低代码概念

低代码(Low-Code Development,LCD),开发者主要通过图形化用户界面和配置来创建应用软件,而不是像传统模式那样主要依靠手写代码。
低代码开发模式的开发者,通常不需要具备非常专业的编码技能,或者不需要某一专门领域的编码技能,而是可以通过平台的功能和约束来实现专业代码的产出。

这里讲到的“低代码开发模式的开发者”,在低代码开发模式的语境中,“开发者”通常指的是低代码平台的使用者(Citizen Developers),而不是开发低代码平台本身的专业工程师。

低代码的目标是降低开发门槛,让非技术人员也能参与应用构建。 例如:一个销售经理可以用微软Power Apps拖拽出一个客户管理系统,无需写代码。一个学校教务员可以用钉钉宜搭设计课程排班应用,仅需配置逻辑。这些用户依赖的是平台预置的模块和自动化代码生成能力,而非自己编写底层代码。

实际上,一个可用的低代码平台的搭建并非难事。首先需要明确,低代码平台解决的最大问题是复用,复用也是目前前端开发中的一个重要课题,特别是当前的主流前端js框架,例如 vue,react 等,都是组件化的开发方式,又如形形色色ui组件库的出现,像 ant-design,element UI 等都是来解决重复造轮子的问题。

在这里插入图片描述

1.3 简易版低代码平台

在前端开发脚手架中,通常会创建一些通用的组件,然后在各个需要这个组件的地方进行引用,来提升开发效率。在脚手架中引用一些ui组件库也是出于这样的目的。
后来,为了防止重复造轮子,通常会对一些成熟的ui组件库中组件根据业务需要进行二次封装,形成一个具有更多功能的区块,例如B端系统中最为常见的列表数据增删改查界面就是这样一个区块。

在这里插入图片描述

可以通过一个json数据来描述这个区块,数据大概是下图所示的样子,包含了这个区块的编码,中文名称,以及可传入到这个区块中的属性及初始属性值,例如这个表格包含的列信息、按钮信息等等。这个json也是低代码平台搭建中最为核心的部分,它在后续介绍的可视化拖拉拽页面设计中扮演极其重要的角色,它是页面设计和页面渲染间串联的纽带。

在这里插入图片描述

当展示类似的界面时,只需要在页面文件中引用这个搜索表格模板组件,再把对应的描述json信息传递到组件内就可以了。但是这样似乎还是采用了编码的方式去解决复用问题,距离低代码还有些距离

这时,

  1. 将这些可动态控制的组件属性通过在线表单进行填写,存储到数据库中
  2. 前端工程中,将使用这个区块模板的页面路由所对应的组件都指向封装好的列表增删改查模板。
  3. 进入到这个页面,只需要将之前存储到数据库的区块描述信息通过api接口获取到,再传递到组件内部,将json数据中设置的模板属性值赋值到组成模板的各个组件上就可以完成这个模板的渲染了

这也是在实现可视化拖拉拽低代码平台之前所使用的方式。这种方式虽然形式上非常简单,却解决了组件复用的问题,并且在调整组件属性时只需要通过在线的表单配置,无需打包、发版

这个界面渲染的流程便是低代码平台的核心逻辑:通过组件元数据拼装成一个页面的描述信息,然后通过渲染器组件将描述信息转化页面dom元素。

「页面路由」是在路由配置文件(比如 Vue 里的 router/index.js、React 里的 router.jsx)中定义的、和具体页面(组件)绑定的路由规则。

在这里插入图片描述

上面实现的流程是不是除了图形化的配置外,基本可以通过在平台上界面的配置实现一个搜索表格页面的开发了,并且不需要专业的编码技能。
当然,上面的过程中所使用到的模板实际是预设好的,只是通过传递进去固定属性的不同属性值进行一些差异化的渲染,一些按钮等自定义功能的扩展也只能通过插槽等形式去实现。但当想要实现其它模板的界面时,就显得无能为力了,因为组成模板的组件是提前预设好的,并不是通过组件像搭积木一样灵活搭建的。

本节内容参考 手撸低代码平台搭建(一)走进前端低代码

2 低代码开发核心-页面设计器

低代码开发平台都是通过拖拉拽可视化的页面设计器进行页面开发的,在这一章节,我们来探索一下页面设计器的实现方式。下图截取了几款优秀的低代码产品的页面设计器界面。

在这里插入图片描述

可以看到,大多数的页面设计器都包含了如下所示的几个区域:

在这里插入图片描述

  • 最上方是操作栏可进行页面的保存、预览、查看json信息、查看代码等操作;
  • 左侧是组件列表当然也可以添加一些切换,让左侧区域支持查看页面树信息、配置数据源等其他操作;
  • 中间是画布区域可以将左侧的组件拖动到画布中,当然也支持画布中组件的复制、删除等操作;
  • 右侧是属性配置区域当在画布中选中某个组件时,可以在右侧的属性配置区域罗列出当前组件可支持动态配置的属性,修改了属性后可以在画布中看到对应组件的样式变化。

2.1 组件列表

首先来看一下左侧的组件列表,列表中的每个组件都需要使用一段json来进行描述,这段json我们将它称之为 元数据元数据中描述了当前组件的中文名称,在列表中显示的图标及描述,和组件可进行配置的一些动态属性。 我们以输入框组件为例,它的元数据大致可以定义为如下的样子:

{
	code: "MyInput",
	name: "输入框",
	desc: "输入框的描述",
	icon: "input",
	props: {
		name: "字段名称",
		label: "label名称",
		labelCol: "",
		wrapperCol: "",
		required: false,
	}
}

那么左侧的组件列表实际上就是这样的一个元数据对象组成的数组遍历而来的。

2.2 画布区域

再来看一下将左侧组件列表的组件拖动到画布是如何实现的。拖动又分为顺序排列布局的拖动和自由布局拖动。

  • 顺序排列布局的拖动是指拖动到画布中的组件是自上而下顺序排列的,可以通过拖动调整上下顺序,当然也可以增加分栏这样的布局类型组件,实现组件的左右排列;
  • 自由布局拖动是指拖动到画布中的组件位置是自由的,我们松开鼠标的位置,就是这个组件在画布中的位置。

考虑到服务的是B端项目,需要尽可能使用户体验保持一致这里采用的是顺序排列布局的拖动。这样用户拖动设计出的页面差异性不会太大,页面布局上又相对规整。

拖动插件 vuedraggable

拖动插件:由于是vue技术栈,选择了vuedraggable插件。像react技术栈也有类似的插件,大家很容易可以搜索到。对于vuedraggable组件的安装及说明这里就不赘述了,直接上demo。

github项目地址 vuedraggable
使用文档 Vue.Draggable的使用
项目创建指导

在这里插入图片描述

上面的demo定义了两个区域,列表区域和目标区域,并定义了两个数组,list1list2。列表区域和目标区域分别使用list1数组和list2数组进行遍历渲染。

当将列表区域的组件3拖动到目标区域时,打印list2变量的数据,就会发现组件3被复制到了list2中,即复制到了目标区域。这就是页面设计器中的拖动原理。

支持拖动的区域需要使用<draggable>组件进行包裹,<draggable>组可以添加onAddonStartonEndmove事件回调函数,可以在这些事件中添加一些自定义逻辑。例如,可以在onAdd函数中对添加到list2数组列表中的对象动态地添加一个唯一值id,用于区分同一个页面拖入两个相同组件的情况。

加唯一id可见前端拖拽-vuedraggable的使用
建议使用时间戳作为唯一id

下面对上面的简单demo稍加改动。

组件列表区域

  • list1数组的中的每一项修改为之前定义好的组件元数据。
  • 可以将定义在元数据中的图标显示在组件列表中,方便我们快速识别出想要拖动到画布中的组件。

跳过

画布区域

  1. 将画布中的组件列表渲染为真实的组件

画布中的列表实际也是通过组件元数据数组进行渲染的,而每个原数据项都对应了一个真实的组件,这样只需要将元数据项替换成UI组件进行渲染就可以了。

注意:可以用动态组件component进行优化。

  1. 画布中组件支持删除、复制、拖动操作

在这里插入图片描述
拖动

demo示例中,目标区域list2是支持可拖动排序的。

复制

画布中的组件是通过list2遍历渲染出的。当点击复制操作时,只需要将当前被点击复制按钮的组件所对应的元数据添加到list2中就可以了。

这里需要注意,在复制元数据的时候,需要将id属性值进行唯一性赋值(时间戳或其他值),这样才能区分被复制的组件和复制生成的组件。

删除

同理,删除操作只需要将list2中的组件通过被复制组件id进行过滤就可以了。

上下移动
原理与复制类似。

2.3 嵌套组件

此次不涉及,跳过。

2.4 属性配置区域

其实到这里,很多小伙伴应该已经大致能够推理出属性配置后画布中组件根据配置进行显示的联动是如何进行的了。

原理同样非常简单。可以对画布中的组件添加点击事件,当点击某个组件时,能够获取到当前点击组件的组件类型,例如输入框、下拉选择等等,针对每一种组件,提前在元数据中的props属性定义这个组件能够进行动态控制的参数,只需要将这些参数以合适的表单形式展示在右侧的属性配置区域就可以了。例如,按钮组件的props中有一个text属性,用来控制按钮的显示文案,那么就在右侧属性控制区域用一个输入框来作为控制这个属性的表单形式,当修改数据时,我到list2中该组件所在的元数据对象,然后将该对象中props属性中text属性值修改为输入框中的内容。每个组件都会接受这个组件对应的元数据props参数,然后根据参数值进行渲染。例如按钮组件,修改按钮的文案时,可以使用props.text进行显示。

2.5 操作栏区域

从以上描述可以看出,一个页面实际就是用一段带有层级结构的json来进行描述的。

保存

保存时实际就是将这段json进行保存操作,可以将json存储到数据库中。

预览

在上面讲解画布区域时,已讲到组件如何通过json进行渲染。预览以及真实的页面渲染实际和画布中组件的展示实现原理完全一致。
其中的区别有两点:
(1)画布中的组件不支持交互操作,这里需要屏蔽画布中组件的交互操作。可以通过css中的after伪类,设置content""来实现。
(2)画布中的组件需要包裹一个div,这个div包含了复制、删除等功能。

其它功能

其实整个页面设计器的核心就是json,其它各种功能也都是围绕json进行。

这部分先跳过

2.6 后记

至此页面设计器的组件列表、画布和属性配置三个区域的联动就都实现了。
目前,页面设计器设计出的界面还是静态的,画布中的组件也都是独立而毫无关联的。在真实的业务场景,组件间的通讯是非常常见的。

在后面的章节中,将会重点介绍低代码中如何进行 组件间通讯 的配置。

3 组件间交互的实现

3.1 前言

第2节主要介绍了低代码平台的页面设计器相关的一些功能原理,打通了页面设计器顶部操作栏、左侧组件列表,中间画布、右侧属性配置四个部分的关系。
能够实现组件列表的展示、组件到画布的拖动,属性配置修改对组件渲染效果影响,并说明了页面设计器中设计好的页面是如何进行渲染的。

虽然看起来实现了通过组件拖拉拽完成页面的开发,但是目前的页面还是无法进行使用的,这是因为页面中的组件都是相互独立而又没有关联的。实际页面中的绝大多数组件都需要进行相互通讯。例如当点击某个按钮时,需要获取到表单组件的表单值进行提交;又比如点击某个按钮会弹出一个弹窗。

本节将重点分析一下在低代码开发中组件间交互的实现方式。

3.2 事件

3.2.1 事件的分类

我们主要依托于事件来进行组件间的交互。为了满足组件与组件、组件与系统、组件与服务端的交互,大致可以将事件分为三个类别:

  • 组件方法:每个组件都会暴露出一些方法供其他组件进行调用。例如表格组件,我们可以暴露出查询表格数据方法;弹窗组件,可以暴露打开、关闭方法等等。
  • 系统动作:有些方法并不属于某个组件,而是系统全局的动作,例如路由的跳转、全局的消息提示、页面加载动画的显隐等等。
  • API调用:这一类主要用于处理组件与服务端的交互,也就是服务端api接口的调用。
3.2.2 事件的定义

系统动作和API调用的定义相对比较简单,可以在vue组件的methods中进行方法的定义,例如可以定义一个request方法用于api的调用,request中调用使用axios封装好的统一的请求方法,request方法支持传入apiurlmethodapi参数等信息。这两类事件为全局事件,可以将这些方法放到mixins中,然后在各个组件中进行引用。

而对于组件方法,需要将组件暴露的方法定义在各个组件的methods中,并在组件加载时进行方法的监听。

window.vm.$on(`${id}-${methodName}`, params => {
  // TODO
})

在组件销毁时取消监听。

window.vm.$off(`${id}-${methodName}`)

上一篇文章页面设计器设计好页面时,生成的组件元数据项中附加了一个id字段,而这个字段在事件监听中也起到了重要作用,能够有效的避免页面中相同的组件重复的触发事件。

做好事件的监听后,就可以使用emit关键字触发事件了。

componentMethod(id, methodName, params) {
  window.vm.$emit(`${id}-${methodName}`, params);
}

在事件配置的时候只需要调用methods中的componentMethod方法就可以了。

3.2.3 事件的配置

第2节讲到,设计器中的每个组件都对应了一段json元数据,修改某个组件的属性时,会到设计器属性配置区域进行表单值的修改,从而修改整个页面json中该组件所对应的这一段json,同理,当进行某个组件的事件配置时,也会对组件的事件属性进行赋值,我们将这个事件属性定义为event。属性值为一段js函数字符串,如下图所示。

在这里插入图片描述
这样,执行事件时,只需要将函数字符串转换为函数进行调用就可以了。

对于代码编辑器插件,推荐一下ace,相对比较成熟,功能丰富,上手简单。这里就不做详细的介绍了,有兴趣的小伙伴可以到ace官网查看。

3.2.4 事件的执行

上面讲到,将事件配置成了一段函数字符串,那如何来执行呢,可以使用eval或者Function去执行,这里选择使用Function

首先定义一个字符串函数解析方法funcStrParse

function funcStrParse(funcStr) {
  return Function("'use strict';return (" + funcStr + ")")();
}

这个方法的参数是一段函数字符串,返回值是一个函数。执行时,只需要调用funcStrParse返回的函数即可。

funcStrParse("这是一段函数字符串")(ctx);

眼尖的小伙伴可能发现了,执行这段函数时,传入了一个ctx参数,实际上,这个ctx参数就是vue组件中的this。上文中讲到,我们会在vue组件中的methods中定义一些系统方法(通过mixin引用)和组件方法。这样,在代码编辑器中编写事件时,就可以通过ctx变量调用vue组件methods中的方法了。

3.2.4 事件的参数

可能有些小伙伴还是有些疑问。现在已经可以通过配置去调用组件中的方法了,那么如何获取到其它组件中的参数呢?

组件参数的传递方式有很多,最基本的就是通过props属性或者通过project/inject进行传递。

考虑到设计器中的组件繁多,并且每个组件都有独特的互不相同的组件参数,这样会导致组件标签中传递的属性过多,并且取用十分不方便。

我们需要将各个组件暴露的参数放到一个公共的地方,这样在使用的时候就非常方便了。这个公共的地方定义到vuex中的store中还是比较合适的。以页面为单位注册storemodule,将所有的组件变量都存到所在页面modulestatepageParams对象变量中。如下图所示。其中id就是组件的id,也就是在pageParams变量中,以组件的idkey,以组件的参数集合对象为value。这样,就可以直接在事件配置中进行使用了。

在这里插入图片描述

3.3 后记

页面设计器中如何实现组件间的交互就分享完啦。在后面的章节中,会介绍一下当页面设计器中提供的组件不足以支撑页面设计时,是否能够通过自定义组件的方式来补充左侧的组件列表,拖拽到画布中,实现业务需求呢?

4 个人实践总结

4.1 功能梳理

首先,总结目前组件的功能如下:

  • 登录组件

    • 整体背景图
    • 左上角人物图
    • 登录注册背景色
    • 登录注册字体颜色
    • 登录注册位置
  • 图片组件

    • 图片展示
  • 任务组件

    • 任务名称
    • 按钮名称
    • 任务配置

4.2 完整功能

先完成一个基本的任务组件,再使用本节事件的方式去优化

目前的效果(2025/11/8)
在这里插入图片描述

支持任务选择和回显。
在这里插入图片描述

4.3 梳理适合使用事件总线的功能点

目前add页面,画布任务组件,配置任务组件,选择任务弹窗之间的功能:

  • 1 add页面
    • 1 更新画布组件配置(由配置任务组件3.1触发)
  • 2 画布任务组件
    • 1 回显(表面不涉及逻辑,实际需要在画布组件更新配置1.1后重新渲染)
  • 3 配置任务组件
    • 1 更新选中组件配置(触发1.1)
      • 1 修改表单内容
      • 2 新增任务
      • 3 选择关联任务
    • 2 打开任务选择弹窗
    • 3 关闭任务选择弹窗
  • 4 选择任务弹窗
    • 1 确定选择任务(触发3.1.3)
    • 2 关闭选择任务弹窗 (触发3.3)
    • 3 选择任务

4.4 使用事件总线实现修改配置刷新画布组件

新增eventbus。这部分直接去看代码实现。

event-bus的方式省去了子组件emit给父组件和父组件接受emit事件处理函数的部分,但事件处理逻辑依然需要。

4.5 事件配置

事件配置,如配置刷新数据的方法。实际发现刷新登录组件的逻辑与任务组件类似,目前可以不处理。

个人觉得事件配置方式比较灵活,但是比较麻烦,需要函数转字符串,如此代码可读性不高,且出错不易定位,先不用。

4.6 vuex状态管理

可以使用vuex管理项目状态(本节3.2.4也是这么建议的),但这个改动对整体功能没有影响,这里不再实现。

2026-3-21 更新
实际做项目时发现vuex足以实现组件间交互,完全不需要事件参与。

低代码平台组件参数共享的核心设计思路 —— 用 Vuex(或 Pinia)做全局状态池,本质就是用 “状态共享” 替代 “复杂事件通信”,既简单又符合低代码 “可视化配置” 的核心诉求。 —— from ai

4.7 功能演示

代码地址:https://gitee.com/abigale1998/low-code
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

4 组件拖动自由布局的实现

不涉及,跳过。

5 自定义组件的实现

稍微看看,还没有到如此程度。

参考内容

  1. 手撸低代码平台搭建(一)走进前端低代码
  2. 手撸低代码平台搭建(二)揭秘页面设计器
  3. 手撸低代码平台搭建(三)组件间交互的实现
  4. 手撸低代码平台搭建(四)组件拖动自由布局的实现
  5. 手撸低代码平台搭建(五)自定义组件的实现
Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐