背景
我所在的部门负责的是活动业务,每天都有很多的营销活动,随之而来的就是大量的H5活动页面。而这些H5活动已经沉淀出了比较固定的玩法交互,我们开发大多数的工作也只是在复制粘贴这种大量的重复工作。
在基于此背景下我开始了低代码平台的开发。
项目架构
首先肯定需要一个可视化编辑器,编辑器主要是以活动为单位进行流转:包括活动的创建、编辑、预览、发布。当然上面流程中的预设模板和组件肯定也要考虑在内。
然后活动搭建完,运营需要去投放,投放侧肯定是H5了,那么对应就要有一个项目来负责对已搭建活动的渲染。渲染端是对客端,也就是投放出去的落地页,用户可以直接看到的。这部分主要是负责对页面的渲染和对应的组件加载、调度,这里采用的是服务端渲染。
然后服务端还需要对上下游提供API。
到这里其实已经可以满足我们最基础的需求了。但这里还有一个不得不提的:组件库。
上面两个比较好理解,那为什么需要组件库呢?组件库核心作用在于复用,我们知道上图中间的画布区域、预览区域以及最终渲染端其实展示都是一样的,这种场景下怎样实现最大程度的复用呢?这个时候就要依附于组件库的能力了。
组件库侧会积累编辑器中经常用到的一些基础组件,像我们这里主要就是文字、图片和素材了,文字和图片比较好理解。素材以形状为主。
细化一下需求:编辑器需要一个前端和服务端;渲染端直接用服务端渲染就行,所以只需要一个项目;组件库可以接入我司已有的组件库;监控统计可以接入我司已有的监控平台。
数据结构及其流转关系
古有“数据驱动视图”,今天我们就结合编辑器视图页面来反推数据。这里思考几个问题:
- 组件Schema应该怎么设计?
- 组件的数据如何去维护?
每个组件都是单一的个体,画布区域由很多个组件组合而成,很容易想到要维护一个组件数组:
components: ComponentData[];
interface ComponentData {props: AllComponentProps;// id,uuid v4 生成id: string;// 业务组件名称name: 'string';...
}
然后当组件被选中时,右侧的属性面板应该展示选中组件的对应属性,这个时候就要维护一个当前编辑的组件数据字段了:
currentComponent: {}
具体交互映射可看下图。
画布区域可以对组件进行添加、删除、编辑操作,就要有对应的方法与之匹配:
// 添加组件到componentData
addComponent(){},
// 编辑组件,更新componentData及currentComponent
updateComponent(){},
// 删除组件
deleteComponent(){}
对于可视化编辑器
这种大型前端项目,须有一个全局状态管理机制去做数据的存储和分发。这样对于数据状态的共享和同步也是很有帮助的。所以以上这些均需要维护在全局的store
中:
state:{
// 所有添加到画布中的组件数据
components: [],
// 当前编辑的组件数据
currentComponent: {}
} mutations:{
// 添加组件到components
addComponent(){},
// 编辑组件,更新components
updateComponent(){},
// 删除组件
deleteComponent(){}
}
大的数据流转关系弄清楚了,接下来就是来设计下每个组件的Schema
,由于组件都是直接来自于组件库,所以要有一些通用的属性:
interface ComponentData {props: AllComponentProps;// id,uuid v4 生成id: string;// 业务组件名称name: 'string';...
}
这里的props更多是和组件本身相关联的属性,主要是一些样式属性,像宽度(width)、高度(height)、外边距(margin)、内边距(padding)、透明度(opacity)、边框(border)、位置(position)、透明度(opacity)等。
除了这些每个组件都具有的基本属性外,像文字组件还具有字体相关的fontSize、fontFamily、fontStyle、color等属性;图片组件还具有图片链接imageSrc属性;素材(形状)组件还具有背景色(background)属性。
组件的Schema看完,我们回到全局,也就是活动维度,看下单个活动的Schema:
interface PageData {id?: number;props?: PageProps;title?: string;desc?: string;coverImg?: string;uuid?: string;setting?: { [key: string]: any };isTemplate?: boolean;isHot?: boolean;isNew?: boolean;author?: string;copiedCount?: number;status?: number;user? : {gender: string;nickName: string;picture: string;userName: string;};
}
除了组件属性外,还需要具备页面id、标题、描述、创建者、状态、是否为模板、属性props(主要包含了页面的宽度、高度、背景色等)
了解了整体大概的数据结构设计后,我们再来整理下数据流转关系:
- 创建作品:用户创建作品,实为初始化了一个json数据
- 保存作品:保存作品其实就是对json初始化的json就行了修改
- 发布作品:作品的发布就是修改了作品的状态(上面
PageData
中的status
) - 浏览作品:作品的浏览就是在C端,服务端根据id和uuid拉取对应页面和组件配置,然后渲染
- 下线作品:有些活动存在有效期,超过有效期后如果运营想下线活动可以直接下线,其实也只是status的修改,同样在C端也要添加对应逻辑
服务端
服务端框架选择的是koa2。
数据库的选择方面,像基础的作品信息(不包含作品内容)比较适合用表格形式存储,对应的也就是mysql
。而作品内容一般都是JSON
,这种更适合使用mongodb
存储。真正的线上环境肯定会存在高并发的场景,这个时候缓存就很有必要了,这里使用的是redis
作为缓存方案。
总结
本篇主要总结了背景、项目架构、技术选型。后面应该会总结下细节方面的难点。