简介
- demo地址
- github:github.com/lx544690189…
技术栈
- react、antd
- 调试打包工具:umijs、parcel
- 表单schema:form-render
- iframe通信:postmate
- 后端:midwayjs2,MongoDB
组件拖拽功能:
组件配置功能:
关于可视化搭建,可以看这篇文章:页面可视化搭建工具前生今世。
1.目标群体
面向开发者和普通用户,快速生成H5页面。有时候低代码比无代码更能提高生产力,脱离“复制粘贴”式的组件复用。对运营人员来说可以快速搭建一个营销页面,对开发来说可以方便的添加、组合组件,结合少量代码去复用之前组件。
2.精准还原设计稿
大部分搭建出来的H5页面,都是采用px单位,更多的是面相普通用户,不讲究像素还原。如果按照现在流行的移动端H5适配方案,设计稿宽度750px,使用rem或者vw单位,页面在各个分辨率的屏幕下展示才一致。这里我们组件最小的粒度是block,开发人员按设计稿还原组件,并暴露出可配置项,像颜色、背景、文案这些,才是交给非开发人员配置的。同时也提供一些基础组件:图片、富文本、视屏等,同时支持搭建一个无需设计的简单页面。
3.友好的组件开发体验
大部分开源可视化项目着重于使用者体验,而物料开发部分则一笔带过。如果你使用过storybook,就会觉得下面组件开发部分跟它十分相似,甚至省去了编写props跟表单的映射代码,可以直接拖拽生成。当然storebook的设计是方便编写、组织、测试组件,项目中一些想法也借鉴了storebook。
4.产出页面体积、版本控制
达到线上标准而不是demo阶段,需要考虑诸如“组件更新后已发布页面该如何处理依赖的组件”。目前版本控制还未实现,主要考虑几种实现方式:
- 每生成一个页面,结合ci触发H5基座的构建,单独为每个项目生成build文件,后续组件更新跟已发布的页面就毫不影响了。
- 每次修改组件发版后,打上一个版本号保存在数据库,并发布到静态资源服务器上,对应页面用到的组件,按照版本号来拉取,也就类似npm包版本的概念
- 完全把组件部分拆分开来,按照npm版本来发包,H5基座安装对应版本组件库,不过这种方式对于开发过于复杂。
技术要点
布局模式:自上而下的排列布局
通常还有一种绝对位置布局,虽然灵活度高但是不利于组件的组合扩展。这里设定最小的组件单元就是占据一行的块级元素,可以在它上面或下面添加组件,可以调整顺序,可以排列组合成更大的组件。
画布:使用iframe
组件单位使用vw,就注定了只能使用iframe。还好元素的drag、drop事件可以跨iframe,并且iframe不用我们去考虑沙箱机制来避免变量、样式的污染,尤其是搭建页面这种多人参与的项目。
iframe间通信可以通过PostMessage实现,这里推荐一个库postmate,能方便的使用异步promise来传递消息、方法调用。
技术点
下面通过如何开发、到使用一个登录领券的组件,来展示其设计思路
1.在对应分类下创建组件,系统将分配一个id来标识此组件
2.本地h5lib目录下创建组件,并导出
这里css按照750px设计稿还原
import React from 'react';
import style from './index.less';
export default function(props:any) {
//正常编写组件,这里我们接受3个可配属性
const {mainColor, fontColor, imgUrl} = props;
return (
<div className={style.loginContainer}>
<img className={style.img} src={imgUrl}/>
<div className={style.formItem}>
<div className={style.lable}>手机号</div>
<input className={style.input1} placeholder="请输入手机号"/>
</div>
<div className={style.formItem}>
<div className={style.lable}>验证码</div>
<input className={style.input2} placeholder="短信验证码"/>
<button className={style.codeBtn} type="button" style={{backgroundColor: mainColor, color: fontColor}}>获取验证码</button>
</div>
<button
className={style.submit}
type="button"
style={{backgroundColor: mainColor, color: fontColor}}
>立即领取</button>
</div>
);
}
// 导出时使用刚才分配的id作为key,并使用import()语法方便后续组件异步加载
export default {
'6045ca8adf8e607d29d0bffb': import('../h5Lib/business/LoginCoupon'),
};
3.拖拽配置组件初始值
上一步我们组件接受三个props:mainColor, fontColor, imgUrl,可以直接拖拽颜色选择器、图片上传控件生成表单项。
这里表单部分借助form-render实现,最终会生成一个描述表单项的schema:
如果这一步对比storebook,就是手动编写knobs部分映射代码了
4.接下来就可以愉快的拖拽生成一个完整的页面了
5.手机访问生成的页面
组件和页面的预览图,通过html2canvas自动生成。
一个搭建好的页面,也可以设置为模板,利用模板可以快速生成相似结构的营销页面:
手机扫描二维码体验:
可以在chrome里查看,组件还实现了异步加载,不必担心组件库的膨胀导致加载缓慢。 其中登录组件需要精确还原设计稿,使用vw单位。
// 异步加载组件示例(首先得打包成异步组件,本项目使用parcel结合import()语法):
const fetchComponents = async function(pageSchema:IPageSchem){
const tasks:any[] = [];
pageSchema.forEach((page)=>{
page.components.forEach((component)=>{
const load = new Promise(async(resolve, reject)=>{
const asyncComponent = componentList[component._id];
if(asyncComponent){
const timeStemp = new Date().getTime();
const loadedComponent = (await asyncComponent).default;
resolve({
_id: component._id,
name: component.name,
component: loadedComponent,
takeUp: new Date().getTime() - timeStemp,
});
}else{
reject(`组件: ${component._id}加载失败`);
}
});
tasks.push(load);
});
});
try {
const loadedComponents = Promise.all(tasks);
return loadedComponents;
} catch (error) {
throw error;
}
};
项目结构
项目分为两块:H5搭建、H5基座。
项目中也尝试使用了一些不错的库(代码会有些混乱):
目前部分功能还在开发中,后端项目暂未开源。觉得不错的话加颗星关注后续迭代。 github.com/lx544690189…
H5搭建:
- dev、build使用umi
- 负责组件开发、管理、拖拽、页面生成的项目
.umirc.ts
中pxToViewPort配置了h5lib
目录px转vw(750px设计稿)- 设计页面时的H5画布(iframe)并不是由下面"H5基座"实现的,它们大部分的功能相同,但是一个仅开发设计阶段使用,另一个要用于生产环境。存在功能和职能差异,故分开。 dev
npm run dev:design
build
npm run build:design
H5基座:
- dev、build使用parceljs
- 负责最终生成的页面渲染
- 动态加载组件
- TODO:可以将页面的json schema直接打入
index.html
,或放到cdn,缩短首屏渲染时间 dev
npm run dev:mobile
build
npm run build:mobile
展望
项目虽然使用react编写,暂只支持react组件,理论上从“schema -> 组件”这一过程,并不存在语言、框架限制,vue、小程序都可以支持,只是需要把H5画布上“schema -> 组件”的中间层替换掉就可以了。