最近重构一个BI项目的仪表板,代码乱成狗,逻辑绕得我脑壳疼!救命!我好难!逼我不得不重新设计一遍整个框架!
1.组件设计需要注意
(1)样式提取出来。
- 提取公共的样式属性作为全局主题样式,然后组件内的样式配置,优先执行。
- 可以弄个主题色管理,什么css的var变量,scss,less等全局变量,或者js改style样式修改都行。
(2)宽高移动端和 pc 端切换要大小自适应
-
常用的响应式方案有栅格布局,rem,vw,百分比等,他们实现的目标就是统一宽度的单位,让其在不同分辨率的屏幕都能呈现较好的排版效果。
-
除了自适应的要求,包裹层要实现布局容器可嵌套组件,拖拽排序和调整大小要流畅。
-
我研究过gridster和GridLayout,他们的自适应效果并不理想,还是会出现排版凌乱的糟糕情况,然后我自己写了个栅格布局,宽度按照设置的网格数量分配,高度取10px的整。我用的是
vuedraggable
加上interact.js
实现一个类似QuickBI仪表板的栅格布局。
(3)数据传入与变量映射
- 数据传入逻辑相同的情况下,需优先考虑组件设计的规范和通用性,生命周期的设置,变量的抛出与传入,组装的规则等都要提前考虑,规则设计最好尽可能的简单,因为不止满足适配系统需求,还要考虑组件分离出去外部使用时的易用性。
- 数据传入后,组件根据变量映射规则,自动处理,生成对应的组件效果。
(4)组件属性配置项可自动生成配置板面
- 组件带有一些个性化配置的属性,没可能每个组件还要手动写一遍配置面板,那么需要设置一套通用的表单组件,满足大部分输入类型和格式,并可自动映射到组件属性赋值,表单输入项之间可相互控制与校验,组件可以直接根据简单的js配置即可生成表单配置板面。
(5)组件可触发交互动作
- 左点击右点击,要对应不同动作,这个可以通过统一的交互,组件通过交互规则配置,分发式统一处理交互事件。
- 还有比较特殊的,比如图表的下钻上卷,组件内部抛出事件,包含需要的预先定义的数据,到达动作处理器,按照定义好的流程执行。
- 建议组件流程的规范化通用化,这样能减少不必要的定制化开发,避免越到后面定制化越多越乱!
(6)动态和远程加载组件
-
系统内置组件建议可以进行动态注册,组件使用的时候,系统主动读取组件的配置,这样就能避免加载注册过多组件,浪费资源。但也有一点小问题,如果组件过大,注册时会出现一会儿小卡顿。
-
上面的样式,属性,交互,数据都设计好规范,那么基础的组件规范成型了,当系统内置组件不能满足客户需求时,客户想要自己定制开发,那么就能按照我们定义的标准,开发组件,打包好后并上传到云端,应用到系统里。
ts
import app from '@/utils/vueApp';
import mapping from '@/resPathMapping';//所有组件远程地址
const compMapping: any = {};//存储组件是否注册
/**
* @param {string} name 组件名
**/
export function registerComp(name: string) {
return new Promise((resolve,reject) => {
if (!compMapping[name]) {//没注册
try {
const path: string = mapping[name]; //获取组件名对应的远程地址
if (path) {
import(path).then((comp) => {//动态加载注册组件
app.component(name, comp.default);
console.log(name, comp);
compMapping[name] = 1;
resolve(true);
});
} else {
reject(false);
}
} catch (error) {
console.log(error);
reject(false);
}
} else {//已经注册过
resolve(true);
}
});
}
注意:必须先注册,在添加渲染组件,不论组件是否注册成功,都要返回,否则promise会卡死在那里
2.编辑界面与预览界面
-
不推荐的做法是编辑界面是完整功能,又有预览又有配置,然后预览只是隐藏配置项。这样导致的问题就是编辑界面功能元素过多,导致当前界面过分消耗内存等资源。
-
要区别这两个东东,两者侧重点不同,编辑界面实现的是配置界面的样式,数据和交互,预览界面解析配置规则,展示最终效果的展示,以及交互的执行。
-
编辑器可以按照SDK的标准来设计,图片等资源先本地缓存,然后最终保存时抛出。数据源等请求规定数据格式,可通过Promise方法来传入,界面则可展示请求数据结果。
-
可以将仪表板拆分成三个部分,组件,编辑器,预览解析器,方便客户二开或集成到其他系统。
3.渲染优化
- 预览界面需要处理两个过程,初始化渲染,操作后渲染
(1)初始化
- 初始化渲染时需要同步url等方式传递过来的值,获取下拉框等控制器的值,然后将这些参数值赋值到组件数据条件里,发起异步请求更新组件数据,所有组件完成渲染,初始化完毕,则可进行操作。
初始化里先渲染生成组件再更新数据,还是先更新组件数据再渲染生成组件都行,前者可以快速展示界面,避免等待空白界面,后者可以避免用户看到数据突变的过程。如果涉及到入场动画,后者可能比较合适。
不过一般数据加载过程都会显示全屏的加载界面,避免空白等待或数据突变的糟糕画面被用户看到,然后加载界面消失,就是最终结果,也可以重新触发入场动画,不耽误效果。
(2)触发交互动作
- 单个触发交互动作,获取事件数据,然后根据绑定组件,生成组件状态列表,给对应组件赋值事件数据,异步请求更新数据,重新渲染组件,更新组件状态列表,当所有关联的组件都更新完,此次渲染完成。
组件状态列表的作用是记录当前组件执行到哪个步骤。
当第二个动作在组件没执行完数据更新就开始触发,而事件数据基于上一个来自其他组件的事件数据时,那么组件状态列表的状态列表的好处就来了。先停止当前执行的请求更新,只完成参数赋值,然后直接执行第二个交互动作的事件赋值,作为更新数据的最新参数标准,这样就能减少请求资源浪费,保证界面数据与操作同步到最新。
-
关联性触发多个交互动作,一个动作触发其他组件的交互动作,比如省市区这样的级联,那么在生成组件状态列表时需考动作触发的虑关联性,汇总这一对多的所有关联组件,先全部事件数据赋值到组件,然后再最终执行请求更新。
-
如果界面中存在过多重复数据请求,可以考虑数据共享池,将每次请求更新的数据结果存储到数据共享池里,一旦有相同请求,则直接取数据共享池里面。这等价于一个本地数据缓存,减少请求,提升效率。但数据请求参数经常变,数据共享池数据会越积越多,这时需要清理定时数据共享池。
- 还有一种方案,以每次操作更新做为单位,在生成组件状态列表时同时收集整理请求,将重复请求的数据整合,相同请求只执行一次,但可以赋值到不同组件,这样就能减少请求了。
4.思考
总体思想就是:不论是组件动态加载还是数据更新,尽量减少资源请求。
除了性能方面的问题,还有好多用户体验的优化,名词的规范化,样式的优化等等,原本基于原BI项目的重构,变成全部推翻从零开始,还要兼容原BI项目,然后越搞越复杂。
(1)产品只要界面效果
他们会抄各个大厂的优秀作品,取其精华去其糟粕,让你一次性做到人家的百分之一百,不考虑开发的时间,不考虑人力资源的对比,不考虑实现逻辑的问题。
于是,数据流向得自己梳理,规范要自己定义,最恐怖的是产品设计不是一次性全出,是一部分功能一部分功能地出,然后新功能与旧功能有重叠的部分,那么意味着你要增量开发,已经搞完的部分如果走不通还得推翻重写。
唉~程序员的宿命!
(2)产品不是开发的队友
产品不会帮你向跟领导争取时间,他们不是开发的队友,不会理解开发。
领导想要的只有结果,不在乎过程。你要人手要资源要时间,还得写方案说服领导!当然领导不会轻易答应的。
然后你找产品下手,让他们删减功能,或推迟到下一期,产品给出的理由XX大厂的产品就是这样设计的,这些功能都很实用,好多项目都有这样的需求,必须做到!
产品最喜欢PUA人的一句话:"这功能那么复杂,对你来说是一种很好的挑战!"
很有道理,但是没时间!
靠自己摆烂式暴躁battle,争取到的结果是第一期,先不搞界面样式,先完成功能。
然后,发现设计图出来,每个界面布局和逻辑都不一样,一点复用可能性都没有,推翻之前大部分的东东,大部分界面都要手动再开发一遍,等价于后续的开发债简直可以累死人。
然而,领导要求的第二期,必须要界面样式全部符合设计,并且还有加其他新功能。
唉~夹缝中艰难求存,苦逼赶项目!
(3)重点!重点!重点!
奉劝大家一句,千万不要入坑低代码、BI和可视化,我想逃,逃不掉,只能硬扛!