Vue数据组件规划与组件二次封装案例
设计平台的时候,不免要使用到各种事先规定好的元数据。这些元数据可能用在不同的页面中,以不同的实例存在。对于SPA,为减少Ajax次数,提高复用率,目前用过的最好的方法即把他们封装为数据组件。同时,将不需要时常获取的元数据存在状态中。这样在利用该组件的时候就可以实现快速无痛的复用。
设计复杂系统常会面临各种元数据的使用问题,如枚举、列表、映射等。这些数据根据即时性,可以大致划分为:
- 极少修改的数据域,如版本号
- 不需要即时同步的数据域,如配置枚举
- 需要及时同步的数据域,如协同操作组件
对于不同的数据即时性,在前端,确切的说在Vue上,我们可以有不同的实现与封装方案。
数据即时性与设计
罕有变化的数据元素
诸如版本号、极少更变的元数据等,可以写在某个meta.js
中。这些字段特点为极少改变且通常为人工运维。为减轻Ajax压力,可以写死在项目内。对于某些无状态自动生成的字段,像copy right中的年月,可以通过即时计算的方法来实现更变,如调moment.js
库。这些元素都有一定的共性,不常变,更变速度甚至可能跟不上版本的迭代速度,无交互状态。于是往往不需要每次打开页面都发请求,这对于降低前端压力、降低交互逻辑复杂度是有帮助的。而数据组件在使用这些元素的时候,通过静态调用即可完成展示。
1 | // meta.js |
Copy Right:
1 | <template> |
不需要即时同步的数据域
不需要及时同步的数据域,可以理解为一次请求/一次打开页面只需要获取一次的数据域。这些往往为配置枚举、映射等。但这些数据又会因状态变化而变化,例如需要响应配置中心的变化。因此,根据是否需要触发即获取将实现划分为:
SPA加载的时候,获取到数据并保存到状态中。
这种实现形式的好处是,数据仅需要被获取一次即可复用。除了SPA本身被加载的时候会有负担,其他时候的负担较小。如:在根组件的mounted
钩子上调用API并写state。下次数据组件仅需要从state读取即可。组件加载或触发的时候,获取数据域
此类需要及时获取、需要在渲染时获得最新数据的组件,会将Ajax封装于自身中。为减少渲染、减少请求量,这些组件推荐被设置为懒加载,且只有触发改变的时候采取获取对应的数据。例如,通过组件懒加载减轻大规模数据组件的加载负担。1
2
3
4
5
6
7// 组件懒加载
const IconList = () => import('components/base/icon-list')
export default {
components: {
IconList
}
}又或者,对二次封装的数据组件,通过状态钩子进行加载。如
iview
Select
组件的on-open-change
。每次触发,刷新数据。这种做法有好有坏:如果每次触发都要加载大量数据,那是极不明智的,证明实时性需要更加细粒度的保证,例如细粒度的父子组件传diff。
即时同步的数据域
即时同步的数据域,例如股票交易数据,往往需要深层次的适配和优化。基于websocket还是基于tcp,用Protobuf还是flatbuffer,是否基于service worker,顺序性,粘包。这样的设计往往比组件设计自身重要。这类组件往往需要拆分工作组件(worker)、api组件(api.js),在浅层渲染组件上调用底层组件。渲染已经不是需要考量的重点,回调挂钩的方式应该反过来进行,即将回调注入到worker中。
协同操作的数据组件
这方面。。。由于不是专业前端。。。看这里。
数据组件二次封装案例
二次封装的数据组件大体上要遵循这些实践方式:
- 调用时,要数据交互跟原生UI组件有一样的设计原则,甚至更方便
- 尽可能降低XHR依赖,依赖模式尽可能松散:如利用好状态和静态变量特性,异常及时捕捉
- 满足原生组件的多状态条件
这几个设计原则,对于项目来说,意义在于:
- 不影响二次拓展和API连贯性,不会因前人写死了代码导致毫无维护和拓展的意义
- 减少数据依赖,阻止异常对外输送
- 不会限制了原生组件功能的使用
例子:iView Select
iview
的Select组件是一个典型的数据组件案例:为提高代码聚合度,通常不会到处散布XHR请求数据并渲染的零散代码,而是将一个选择类别进行二次封装。
这种情况下,只要对数据实时性不会有很高的要求,较为优雅的实践是,在加载页面时通过根mounted
钩子发XHR将枚举、映射存储到状态中。数据组件在计算属性上导入相应的状态,通过v-for
渲染Option
。
这个时候,我们设计时要尽可能满足Select
的API设计思路:
- 满足
clearable
、filterable
、muliple
、disabled
等属性的等价性,因此需要把这些属性当作自身的属性; - 满足
value
的双向绑定特性,通过计算属性直接绑定Select的value - 在设计multiple的时候,要注意返回的是数组还是字符串
- 对钩子事件尽可能实现(并非完全重现,根据需要执行)
代码样例:
1 | <template> |