首页 >> 大全

Tangram 2.0——猫客页面内组件的动态化方案

2024-01-02 大全 29 作者:考证青年

2.0 库 iOS 背景 技术背景

一直以来,无线应用都在不断寻求动态化页面的解决方案,在阿里巴巴集团内,除了风风火火地 Weex 项目外,各个团队都有大大小小的解决方案。我们猫客一直持续基于方案来解决页面动态化的问题,然而在面对持续升级的业务需求时,原有的开发模式也慢慢变得无法胜任,本年度以来,我们 体系在各个层面都进行了大跨度的技术升级(可参考文章天猫APP改版之首页架构&开发模式全面升级),本文再详细介绍一下页面内组件体系升级方案。

老组件体系的问题

在原有的 体系里,主要解决了页面内布局结构的动态化能力,通过 json 数据描述可以组合出常用的页面结构。然而页面内具体的坑位样式,我们称之为业务组件,是采用常规的 代码开发的,除非内置了足够多的逻辑,否则组件的样式调整或者新组件的开发都要发布版本,无法满足业务节奏;当然我们也尝试过使用 Weex 开发业务组件贴到页面上,但是在体验和性能上还是有较大的缺陷。

所以总结起来,就是两点问题:

业务组件无法动态更新;现有的动态组件方案较重,影响性能和体验; 解决之道

对于上述问题,解决思路其实是比较通用的,要动态更新界面视图,就需要用界面模板描述视图,模板与数据分离。将动态下发的模板和数据在端上绑定渲染。要提升性能,也有三大着力点——减少视图层级与个数,结构尽量扁平化;异步布局渲染流程,解放主线程计算量;回收与复用组件,减少内存开销。

新的组件体系就是在模板化描述视图,动态更新视图,减少视图层级几个方面做文章,至于组件的回收复用,则是在页面级别统一完成;而异步布局渲染流程,则是后续的优化方向。

新的组件方案称之为 ,简称 VV,也称为2.0组件,它的设计遵循以下几个思路:

以了一种虚拟化开发基础组件的技术,使用方只要按照指定协议实现一个基础组件的尺寸计算、绘制逻辑、布局逻辑,即能实现在宿主容器的 里实现直接绘制 UI 内容的,让最终渲染出来的视图结构呈现扁平化,提升组件渲染性能。同时为了解决虚拟化 View 带来的原生 View 的能力损失的问题,它支持加载和渲染原生基础组件,两者组合产生合力,既能减少开销,又能满足特殊场景下的业务需求。内置实现了一系列基础组件,可以让使用方直接上手尝试;而搭建业务组件的方式采用 XML 模板来编写,配套 XML 模板更新 sdk,这使得业务组件动态更新成为了可能。XML 模板里还支持写数据绑定的表达式,在样式动态化、数据动态化的场景下能非常方便地实现业务需求。XML 模板里涉及到的基础节点、属性、字符串资源等都被提前编译成二进制资源,客户端加载通过加载编译后的模板数据来创建视图。 设计方案 整体架构

先从整体上预览一下整个方案的大体结构:

_组件化web设计原理_组件平台

自下往上,自左往右的顺序介绍各个模块:

运行流程

有了上述基础,当我们要开发新的业务组件的时候,除了有新增 逻辑的需求场景(比如新增视频功能),大部分需求都可以告别原生代码的编写,转而编写组件模板。

组件化web设计原理_组件平台_

先编写业务组件的模板。通过工具将模板数据编译成二进制数据。客户端加载二进制数据可以有两种路径,一是直接打包到客户端里,写代码加载,另一种是发布到模板管理后台,客户端在线更新到模板数据。不论哪种方式加载二进制数据,客户端接下来的工作是解析二进制数据里,比如校验版本号,合法性,读取头信息等等。等要真正创建组件的时候,根据组件名称找到二进制数据,从中解析并创建出真正的组件模型数据。从模板里创建在组件往往不含有业务数据,因为业务数据是动态性的,用户需要获取到业务数据绑定到组件上,组件的属性里可以写表达式来指定使用哪一个数据字段。

值得注意的是,在上述架构及流程里,描述了一个完整的实践经验,但对于本方案来说,核心点在于提供了对组件从编写到展示流程的实现,其周边的配套设施,并没有内置在框架里,包括客户端上的模板管理、更新、注册模块,以及后端的模板发布服务,因为这些模块往往涉及业务逻辑,且与各个应用的基础设施相关,内置在框架里反而限制了使用方的接入。这里提供一些可供参考的经验:

模板管理后台要能对模板的进行发布、更新,并且按照客户端版本、平台、组件版本、生效优先级等几个维度来管理模板;模板文件可以存放到 CDN 上供客户端下载,管理平台只是对比下发远信息;下载文件要做足够的校验;客户端要内置一份打底的模板数据,这样不至于因为模板不存在而出现空窗;客户端可提供一个统一的模板管理模块,面向全应用提供服务,在合适的时候请求管理平台检查有没有更新,比如启动、用户刷新、推送指令的到达,并且负责下载、文件校验、通知页面刷新等功能;页面刷新可以做优先级区分,比如高优先级的模板更新主动去刷新下页面,而低优先级的可以等二次进入页面或者刷新页面的时候生效; 几个核心设计 组件的基础模型

对于组件,我们做了如下定义,每一个基础的原子组件或者容器组件都会有以下属性,自定义的基础组件应当继承自基础定义并做扩展。

名称类型默认值描述

id

int

组件id

int/float/enum(/)

组件的布局宽度,与里的概念类似,写绝对值的时候表示绝对宽高,表示尽可能撑满父容器提供的宽高,表示根据自身内容的宽高来布局

int/float/enum(/)

组件的布局宽度,与里的概念类似,写绝对值的时候表示绝对宽高,表示尽可能撑满父容器提供的宽高,表示根据自身内容的宽高来布局

enum(left/right/top///)

left|top

描述组件在容器中的对齐方式,left:靠左,right:靠右,top:靠上,:靠底,:垂直方向居中,:水平方向居中,可用或组合描述

int/float

组件宽高比计算的横向值

int/float

组件宽高比计算的竖向值

enum(X/Y/NONE)

NONE

组件在布局中的基准方向,用于计算组件的宽高比,与、配合使用,设置了这三个属性时,在计算组件尺寸时具有更高的优先级。当=X时,组件的宽度由和父容器决策决定,但高度 = width * ( / ),当=Y时,组件的高度由和父容器决策决定,但宽度 = * ( / )

int/float

最小宽度

组件化web设计原理_组件平台_

int/float

最小高度

int/float

左内边距

int/float

右内边距

int/float

上内边距

int/float

下内边距

int/float

左外边距

int/float

右外边距

int/float

上外边距

int/float

下外边距

int

背景色

null

背景图地址

int

边框宽度

int

边框颜色

enum(//gone)

可见性,与里的概念类似,:可见,:不可见,但占位,gone:不可见也不占位

enum(left/right/top///)

left|top

_组件化web设计原理_组件平台

描述内容的对齐,比如文字在文本组件里的位置、原子组件在容器里的位置,left:靠左,right:靠右,top:靠上,:靠底,:垂直方向居中,:水平方向居中,可用或组合描述

方案内内置了一系列基础组件,完整的组件列表如下:

虚拟组件

上文提到虚拟化开发的组件的技术,简称虚拟组件。很多做性能优化的方案、建议都会提到采用 直接绘制的方式来减少 View 的个数,虚拟将这个开发流程做了抽象与规范,可以让开发人员像定义原生组件一样定义虚拟组件。

具体来讲,基础组件需要遵循一个接口的规范,这个口定义了渲染过程中需要的三个流程:计算尺寸阶段、布局阶段、绘制阶段;定义这个三个阶段是为了更好的与系统平台特别是 平台对接,因为在 原生平台下也会有这个三个阶段,在 iOS 平台下则也需要按照本方案里要求的规范去处理。计算尺寸阶段定义要触发一次尺寸计算,需要对其包含的子组件进行计算调用;布局阶段定义了要触发一次布局,将子元素按照计算好的位置尺寸排布,也要对包含的子组件进行布局调用;绘制阶段定义要进行视图绘制,当然也要对起包含的子组件进行绘制的调用;对于虚拟组件,就在这些接口里实现相关逻辑,而对于原生组件,在这些接口实现里调用原生组件的对应逻辑。

不论是虚拟化组件还是原生组件,都采用上述相同的模型来定义,再加上相同的尺寸计算接口、布局接口、绘制接口,这样对于宿主容器来说,包装在内部的组件就不分虚拟化还是原生,一视同仁,暴露给外面的接口也是一样的,只要将宿主容器像普通的 View 一样添加到的视图界面上,就可以在后续的渲染过程中显示出来。如果虚拟组件使用的越多,View 的个数就越少,对于系统来说层级越扁平。以下图示例的组件来说,最终呈现的 View 只有宿主容器和两个图片组件,如果将图片也用虚拟化的方式实现,最终 View 只有一个宿主容器,而界面仍然保持不变。

组件化web设计原理__组件平台

二进制文件的格式

通过 XML 编写的业务组件,并不直接在客户端里运行使用,而是先进行一次二进制序列化操作,原始的 XML 模板文件保存成文件的时候,就是以纯文本的形式存在,会包含很多冗余信息,比如空格、换行、还有重复出现的字符串等,文件体积比较大,以xml解析器去解析的时候,也会需要大量字符串操作,效率和性能不能达到最优。而将它编译成二进制格式,会避免这些问题,比如文件重复出现的字符串只保留一份,通过字符串索引去引用它,所有的组件类型也都会被转换成一个数字索引,在客户端内通过数字索引反过来找到对应的类实例化。这样文件格式会非常紧凑,体积更小。整个设计也借鉴了 系统编译模板文件的思路。它的具体格式说明如下:

_组件化web设计原理_组件平台

按照图中从左往右、从上往下的顺序分别说明每个段的作用:

绑定数据的表达式

开发业务组件的时候,基础属性或者样式往往不能在模板里直接写死,而是需要从数据里获取,所以引入了用户数据绑定的表达式,语法和实现上目前比较简单,参考了很多同类的设计,尽可能符合开发人员的直觉。

语法上以 ${ 开头,以 } 结束。对于Map,通过 . 操作符进行访问,对于 Array 或者 List 通过 [] 操作符进行访问。

比如:

${benefitImgUrl}
${data[0].benefitImgUrl}

用来给那些需要根据数据中某个字段来设置值的属性,语法上以 @{ 开头,以 } 结束,中间部分为表达式的具体内容。

条件表达式 ? 结果表达式[1] : 结果表达式[2]

当条件表达式成立的时候,使用结果表达式[1],否则使用结果表达式[2]。 其中: 条件表达式支持布尔类型、字符串类型、、。 以下场景均为 false:

比如:

@{${logoUrl} ? visible : invisible }

考虑到篇幅限制,不能将上述架构和流程中的每一细节完全展开,详情可以参考苹果核这里的文档。

效果 与 及 TAC 结合

方案是 的极大补充,可以解决80%场景下的动态化需求,而 依赖的数据则通过 TAC 提供解决,三者结合可以形成一个闭环,让一个开发从端到端地解决整块业务的开发。

组件动态下发

以双十一期间为例,90%的双十一业务组件都是动态下发的,且随时可根据业务节奏调整。

_组件化web设计原理_组件平台

组件平台_组件化web设计原理_

组件平台_组件化web设计原理_

展望

尽管在功能流程上已经逐步稳定,能承载起日常及大促的需求变更,我们的方案还是有很多不足之处的,比如我们期望更高的运行效率、更加扁平化的UI结构、更加方便的开发体验,对此也做了更进一步的规划建设:

功能计划

提供更加完善的文档和教程、Demo,内外版本同步,建立以 为中心的迭代开发机制

17年12月

组件创建、布局计算、数据绑定机制优化,提升性能

18年1月

重构模板编译工具,提升编译开发体验

18年1月

提供预览服务,提升开发效率

18年3月

提供配套的后端数据服务与基础设施,即 TAC 平台开放

18年3月

附录 2.0 主要更新说明 组件模型的概念升级,从原来的『卡片』+『组件』升级成『布局』+『组件』,即原来的『卡片』认为是一种具有布局能力的组件,具备嵌套另一组件的能力;页面结构优化,页面下可以直接挂载组件,不需要嵌套一层布局;组件类型的语义化,从原来的 1、2、3、4…等数字枚举类型定义,升级成字符串类型的定义,兼容解析原有的数字枚举定义;更好的嵌套布局实现,流式布局在模型描述上支持多层次的嵌套,并优化了 端上的实现方式; 去重的实现,同一层级的容器组件或原子组件直接,支持外边距 的去重,使得动态数据下控制间距更方便;支持 ,无论是容器组件还是原子组件,支持在其样式上配置 , 值越大,绘制层次越高;升级组件开发方式,引入动态化组件开发技术,提升组件动态性,实现组件样式的高效渲染与动态更新; 其他相关的 库

iOS

工具

摘自:苹果核 - 猫客页面内组件的动态化方案- 2.0

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了