1. 低代码
优缺点
优点:
- 它的本质是提效,提效的同时给了自由度(以较少的成本达到想要的结果)
- 它的优势是可视和快速
- 它的能力源自于物料(组件)的能力
缺点:
- 上手成本高
- 不好维护和迭代
- 换个同类型组件都得考虑一下,如果换个人还得重新理解,还不好调试,不好定位问题,也不好确定本次改动对之前功能的影响
- 不好做性能优化
基本实现
物料区
-
组件的分类:
- 容器组件(这类组件主要用来协助布局和嵌套)
- 基本组件(常见的有图片、文本、输入框、视频等)
- 集成度稍高一点的组件(表格、表单、图表、自定义组件、业务组件)
-
如何加载组件?不管什么情况下,在前端加载文件只有两种方式:
- 一个是
import() - 一个是
<script>
- 一个是
-
如何扩展自定义组件?
- 可以直接把开发好的组件发到 npm 上,把 npm 当做物料平台用
- 如果这个第三方组件是已有的,我们需要简单适配一下(适配器模式),也就是这个第三方组件需要实现 IComponent 接口
// 方法一:import
const name = 'Button' // 组件名称
const component = await import('https://xxx.xxx/bundle.js')
Vue.component(name, component)
// 方法二:script
function loadjs(url) {
return new Promise((resolve, reject) => {
const script = document.createElement('script')
script.src = url
script.onload = resolve
script.onerror = reject
})
}
const name = 'Button' // 组件名称
await loadjs('https://xxx.xxx/bundle.js')
// 这种方式加载组件,会直接将组件挂载在全局变量 window 下,所以 window[name] 取值后就是组件
Vue.component(name, window[name])
画布区
那画布区是怎么渲染出来的呢?我们会有一个 componentTree 来递归渲染拖拽出来的元素,然后各自按照组件类型来渲染。
核心思想:就是我们所有的操作,不管拖拽也好,修改元素属性也好,还是调整元素位置,都是对 componentTree 这个数据进行修改,单纯的对数据进行操作,比如追加元素,就往 componentTree 的 children 里面 push 一个元素即可;如果要修改一个元素的属性值,只需要找到对应元素的数据修改其 props 值即可。画布编排的本质就是操作组件节点和属性。
物料区只负责渲染组件列表,以及触发拖拽放下的事件,之后就是触发修改全局的 componentTree,再之后就是触发画布区的重新渲染。
function renderNode(node) {
if (!node) return null;
const component = components[node.componentName];
const props = compute(node.props);
const children = node.children.map(c => renderNode(c));
return renderer.render(component, props, children);
}
renderNode( componentTree);
设置区
通常会支持三种基本的设置:props 、 样式 、 事件
- 一个常常提到的问题就是如何实现联动,比如字段 2 的显隐依赖于字段 1 的值,实现方式:
- 利用全局数据了,比如我们把字段 1 和字段 2 都放在全局数据中,然后在字段 2 中新增一个 visible 的属性设置器,其值是一个模板表达式,形如:
{{ globalData.field1 && ... && globalData.fieldN }},因为数据是全局的所以很方便能够直接获取到,在实际渲染的过程中就会动态执行上面那个表达式来确定组件渲不渲染。此外,因为数据是全局的,跨组件或者跨页面共享数据也会变得轻而易举.
- 利用全局数据了,比如我们把字段 1 和字段 2 都放在全局数据中,然后在字段 2 中新增一个 visible 的属性设置器,其值是一个模板表达式,形如:
顶部工具栏
通常可以有前进、后退、清空等操作,但是这些操作并不算是必须的,它们通常以插件的形式存在
注:
- 物料区也可以有插件:主要表现就是用脚手架来扩展物料
- 画布区也可以有插件:比如选中组件的时候可以扩展复制、删除、辅助线、上移下移等功能
- 设置区也可以有插件:比如颜色选择器,可以追加自定义表单项
状态管理方案
const componentSchema = {
version: "1.0.0", // 当前版本号
// 组件描述
componentList: [
{
componentName: "Button",
package: "@jc/next",
version: "1.0.0",
destructuring: true,
},
{
package: "@jc/next",
version: "1.0.0",
componentName: "Page",
destructuring: true,
}
],
state: { // 全局状态
name: "页面名称"
},
componentsTree: { // 画布内容
componentName: "Page",
props: {},
children: [{
componentName: "Button",
state: {},
props: {
type: 'primary',
size: "large",
style: {
color: 'red'
},
className: 'custom-button',
onClick: { // 事件绑定
type: "Function",
value: "function(e) { console.log(e.target.innerText) }"
},
}
}]
}
}
拖拽缩放功能
第三方插件
vue3-draggable-resizable: 用于拖拽调整位置和大小的的组件,同时支持冲突检测,元素吸附对齐,实时参考线
vue.draggable.next:基于 Sortable.js 的兼容 Vue 3 的拖放组件
2. 低代码 + AI 方案调研
基于以上的背景,我们从 AI 辅助搭建、修改页面、辅助开发编程、辅助产品需求抽象等维度对市面上的 AI 低代码平台调研。
| 解决方案 | 公司/团队 | 功能 | AI 搭建页面 | AI 修改页面 | AI 辅助编程 | AI 辅助需求抽象 | 核心模型能力 |
|---|---|---|---|---|---|---|---|
| 易鲸云 | 炎黄盈动 | 管理端页面搭建 | ✓ | ✘ | ✘ | ✘ | 未公布 |
| 叨叨编程小助手 | 一刀云 | 脚本编写 | ✘ | ✘ | ✓ | ✘ | ChatGPT 开放接口 |
| Thor | 腾讯 | 管理端页面搭建 | ✓ | ✓ | ✘ | ✘ | ChatGPT 开放接口 |
| Informat next | 织信 | 管理端页面、图形化编程搭建 | ✓ | ✘ | ✓ | ✘ | ChatGPT 开放接口 |
综上,目前市面上的 AI 低代码平台大部分都是依赖于 OpenAi 团队的 ChatGPT 开放接口
3. 低代码结合 AI 的开发方式
- 组件是确定的,但组件的样式等配置由大模型来生成:大模型核心负责页面样式、文案等配置,可提供针对不同领域场景的配色、主题方案,再由相应的桥阶层来转化为低代码的 json tree,最后再由 json tree 来结合相应的低代码组件渲染页面。
- 适用于所有
基于 Schema 驱动的低代码平台
普通的低代码实现
基于 Schema 驱动的低代码平台中,生成一个网页,大概需要以下几个步骤:
- 根据业务需求,选择合适的区块
- 将区块拖拽到编辑器画布中
- 在编辑器中编辑区块的属性
- 预览、发布网站
结合 AI 技术的低代码实现
AI 的优势:
推理、拓展、学习、分析
结合 AI 技术实现页面自动生成,可以极大地提高网站建设的效率。大概有以下步骤:
- 用户输入一段公司描述,例如:我是一家物联网公司,主营汽车配件
- AI 根据这段输入,分析出 Web 页面可以由哪些楼层(
Section)组成,并推理出一个这些 Section 的信息 - 根据 Section 信息,通过向量匹配,在自家物料库中,匹配出合适的区块(
前端组件) - 根据匹配到的区块的 interface,利用 AI 推理出合适的区块属性(
组件数据) - 结合区块和区块属性和 Schema 协议,生成标准的 Schema
- 将 Schema 放入低代码编辑器,用户可以进行二次操作,预览、发布网站
总结
- 利用 AI 替换了原来需要用户手动操作的
步骤 1 ~ 3,使得整个网站建设过程更加智能化、高效。 - 其中 1、2、4 需要通过自定义的
prompt实现,我们修改了prompt,以便在生成 Section 的同时,让大模型帮助我们筛选出合适的区块分类。
prompt 修改示例:
you are a webpage developer. your job is generating a document base on the user input. the document should follow this format:
Section1
Title: (same language as user input) a title for this section's content
Content: (same language as user input) a paragraph, about 100 words of this section
Keywords: some keywords summary of this section content
Components: (only one)Depending on the Content of this section Title and Content, select an appropriate value in ['AboutUs', 'Team', 'Timeline'] to describe the appropriate component that can be used to display this section on the web page
...(this Section/Title/Content/Keywords/Components should repeat 4 times)
Begin!
USER_INPUT: {data}
结合 Section,填充区块的 props
interface AboutUs {
/** 标题 */
title: string;
/** 描述 */
desc: string;
data: Array<{
/** 图片 */
image: string;
/** tab 文案 */
tabText: string;
/** 按钮文案 */
btn: string;
}>
}
生成数据:
{
"componentName": "AboutUs",
"props": {
"title":"物联网汽配 专注于汽车配件业务",
"desc": "物联网汽配是一家专注于汽车配件业务的公司,致力于为客户提供高品质的汽车配件和优质的服",
"data": [
{
"image": "https://picsum.photos/24/24?random 1",
"tabText": "物联网汽配",
"mediaTitle": "专注于汽车配件业务",
"mediaDesc":"物联网汽配是一家专注于汽车配件业务的公司,致力于为客户提供高品质的汽车配代",
"btn": "了解更多"
},
{
"image": "https://picsum.photos/24/24?random2",
"tabText": "汽车配件",
"mediaTitle": "高品质",
"mediaDesc": "我们提供高品质的汽车配件,以满足客户的需求。",
"btn": "了解更多"
}
]
}
}
低代码结合 AI 编辑页面
- 接受用户的自然语言需求的输入,请求 ChatLowCode 服务,获取页面 Schema Json数据。
- 新旧页面 Schema Json Diff,差异化更新编辑器画布中的页面。