在降本增效的大背景下,Low Code 这两年被大家讨论的比较多,社区里也有很多不错的解决方案涌现出来。对于前端来说,页面搭建是一种具体的 Low Code 实践形式,是一种已经被证明有效的技术和业务提效手段。
通观社区里的主流实践,页面搭建目前还只能解决一些垂直领域的问题,比如电商营销、中后台管理页面等。换句话说,适合使用页面搭建来解决的问题,通常具备如下两个特点:
除了以上两个特点以外,还有一个常见特点,就是资源瓶颈的问题。人力资源紧缺,又很难在短时间内招到满意的人。
当然,在一些特定领域内,比如电商营销,还会有需求比较高频,开发时间短,上线时间紧等特点。比如一周好几个活动,时间要求又很高,需要即刻上线的情况。
页面搭建系统,简单来说,就是通过可视化加自动化的形式来完成交付页面的生产过程。这个生产过程会屏蔽很多专业领域的知识(比如编码、技术概念等),同时可以极大的复用已有的工作成果,最终实现成本降低和效率提升。
从技术角度来说,页面搭建系统是将 HTML、CSS、JS 组装成页面。对于现代前端开发来说,都是开发组件,然后通过框架来完成页面渲染。因此,页面搭建系统实际上是完成组件到页面的拼装工作。
组件是页面搭建系统中最小的组成单元。不管是基于 React 还是 Vue 开发的,亦或是基于 Web Component 开发的,组件都需要对外提供一定的接口,使得外界可以使用组件。这些接口,我们可以通俗的理解为 props。
当页面搭建系统成长到一定规模,系统内的组件会越来越多,会慢慢衍生出组件库乃至组件市场。这时候,我们就需要有一些辅助系统来对组件进行管理。
模板是组件的固定集合。当某些页面结构重复出现,变化的只是内容时,比如一些活动页面,我们可以将这些页面抽取成模板。与组件一样,模板也会逐步演变出模板库和模板市场。
我们以组件为例,来看看组件的管理方法。通常,有两种组件管理方法。
第一种方法通常在项目初期被采用。在项目初期,整个系统还在验证和打磨阶段,组件相对较少。与页面搭建系统放在同一个代码仓库中,管理复杂度低,使用方便,可以实现快速迭代。但是当系统逐渐成熟,接入的业务越来越多,组件数量呈指数型增长。通过统一的代码仓库来管理不管是从代码复杂度还是从管理沟通复杂度来说,都已经不太现实。这时候就需要使用第二种方法了。
第二种方法,将组件发布成独立的 npm 包,页面搭建系统通过一定的方式识别和加载组件包,实现组件包的接入。这种方式可以解决组件数量指数增长的问题,但是实现成本也比较高。通常来说需要约定一个组件接口规范,组件需要实现这个接口规范才能被系统识别并使用。但是也有做的比较好的,比如阿里的云凤蝶,会通过云端服务的形式,借助于一些工具对 npm 包进行分析,推导出组件有哪些能力。这样对组件开发约束更小,可以直接复用已有的组件,但是技术挑战也更大。
页面搭建系统的核心应该就是可视化编辑器了。通常长下面这个样子。
可视化编辑器主要有两个问题需要解决。
这里说的页面布局指的不是最终交付的页面布局,而是在生产页面的时候,编辑器内的布局方式。
为了能让不懂技术的人完成页面的搭建,因此页面搭建系统需要屏蔽一些技术细节。所以可视化编辑,通常都是通过拖拽等形式来实现页面结构的布局。
一般来说,可视化编辑器有多种布局方式可供选择。不同的业务场景对布局灵活性要求不一样。
在画布上会先确定布局方式,然后在里面填充组件。这种布局方式多用在 H5 页面中。比如在营销场景中,这种布局方式用的比较多。
自由布局就是可以在画布上随意拖拽放置组件。页面搭建系统会通过一系列的方法最终将画布中的组件的相对位置处理成页面中的位置,并能自适应屏幕尺寸的变化。
阿里的云凤蝶,因为主要解决的是中后台的页面搭建问题,页面结构相对比较复杂,采用的就是自由布局的方式。这里面技术复杂度要比采用 Flex 或者 Grid 布局的系统要高很多。
首先要能正确识别出组件的父子关系,换句话说,就是能够在用户拖拽的画布上正确识别组件树。这里面会用到一些位置计算的算法。
其次要将画布中组件的位置关系正确的反应到页面中,并能处理好自适应问题。因为画布中组件的位置都是绝对定位的,实际页面中不太可能是绝对定位,要做转化。通常需要借助于行列栅格化等算法来做。
在可视化编辑器中编辑页面的时候,用户通常需要增加和删除组件,同时还需要对组件数据进行编辑。因此,一般情况下,可视化编辑器都需要一个状态管理器来管理整个应用的状态。
当然基于事件来同步组件数据实现起来比较简单,但是当页面规模比较大的时候,对事件的跟踪和管理将会变得非常复杂,成本指数上升。因此,我们这里选用外置的全局状态管理方案。
适用于不同业务场景的可视化编辑器状态设计可能不同,我们简单探讨一下。
通常来说,全局状态主要处理组件的增删改,即画布中拖拽和删除组件以及在组件属性编辑区域修改组件属性。因此,我们可以简单设计如下:
{ state:{ // 所有添加到画布中的组件数据 componentData:[], }, reducers:{ // 添加组件到 componentData addComponentData(){}, // 编辑组件,更新 componentData editComponentData(){}, // 从 componentData 中删除组件 delComponentData(){} } }
整个应用的数据都保存在 componentData
中。 当在画布区域添加和删除组件的时候,编辑器通过 addComponentData
和 delComponentData
来更新全局的组件数据。当右侧组件属性编辑区域修改组件属性的时候,通过 editComponentData
来更新全局的组件数据。
有了基本的全局状态设计,剩余的就是做一些粘合工作,比如组件属性编辑区域,会有一个 Form 表单来编辑属性,我们需要将表单的数据变更与全局状态做粘合。常见的例子是字段 onChange
到 editComponentData
的粘合。
如果是自由画布,则需要处理一些拖拽动作,然后咋对应事件中粘合 addComponentData
和 delComponentData
。
可视化编辑器内有很多技术细节问题需要解决,在页面可视化搭建工具技术要点这篇文章中,讨论的比较多,可以看看。
一般情况下,如果页面比较简单,比如营销业务中的活动页面,上面的设计足够解决问题。但是如果是在中后台业务场景下,页面会有一定的复杂度,上面的设计就显得单薄了。在中后台业务场景下,组件之间经常存在关联关系,同时页面结构也更加复杂,单纯的 editComponentData
难以满足业务需求。
比如,组件 A 会依赖组件 B 的变化,组件 B 又依赖组件 C 的变化,这在 Form 表单场景中非常常见。
因此,我们需要借助其他的方案来解决。比如使用一些响应式的方案。nx-js/observer-util 是一个不错的响应式方案。
编辑好页面,后面就是发布页面了。其实在编辑的时候,通常会有一个预览功能,因为与页面发布的原理是一样,我们统一放到页面发布里面来说。
通常页面发布有两种方式,一种是直接发布成静态页面,一种是借助于渲染 SDK 动态的获取页面数据完成渲染。
直接发布成静态页面,对于业务来说使用最为简单,只要控制好页面的缓存策略即可实现页面更新。缺点是适用性比较差,在一些需要内嵌页面的场景下,可能只有 iframe 等比较有限的选择。
发布成静态页面,实际上有多种技术方案可供选择。
可以直接在发布页面的时候,在服务端通过 webpack 等构建工具,根据每个页面组件的不同,构建页面专属的静态资源,避免全量引入所有的组件。
也可以将页面需要的组件信息导入到 HTML 文档中,然后在浏览器解析文档的时候,通过渲染 SDK 来加载组件,渲染页面。这与动态渲染的工作机制就非常类似了。
通过 SDK 渲染,适用性广、灵活性高,缺点也比较明显,系统需要额外提供一个页面数据获取接口,对系统的可用性要求一下提高了很多。同时,SDK 版本的升级管理也是一个需要考虑的问题。
动态渲染,需要 SDK 根据接口返回的信息加载每个组件的代码。换句话说就是加载每个组件的 js 模块。
模块加载方案有很多,比如可以直接将组件构建成 umd 模块,然后浏览器中直接使用。也可以通过 SystemJS 等模块加载方案来实现。
加载完组件模块以后,SDK 就可以完成页面渲染了。
上面概念性的讨论了很多页面搭建系统的内容,总体来说,页面搭建系统流程不是很长,核心就在可视化编辑器方面。
考虑到会有非开发同学参与页面的生产过程,因此整个系统是否能够支持业务需求同时真正的做到降本增效,很大程度上由可视化编辑器是否足够易用决定。
对于可视化编辑器来说,要想易用性好,很多细节需要打磨,技术投入会非常大。比如做一个媲美 Sketch 的自由画布的投入成本绝对比只能简单添加和删除组件的画布的投入大。
因此,在考虑做页面搭建系统之前,需要明确的问题是,当前业务需求是否真的适合做页面搭建。在做页面搭建系统的时候,也需要高度结合业务需求,有针对性的选择技术方案,才能获得一个比较满意的投入和产出。
关注微信公众号,获取最新推送~
加微信,深入交流~