这是Jerry 2021年的第 14 篇文章,也是汪子熙公众号总共第 285 篇原创文章。
在本篇文章之前,Jerry 印象最深的幽灵,应该要算《星际争霸I》里人族能够隐形的空中单位 Wraith( 幽灵战机 ),以及能施放核弹的 Ghost( 幽灵特工).
上周 Jerry 做 SAP Spartacus 开发时,接触到一个新的和幽灵相关的术语:
Skeleton Design(Ghost Design)
读了帮助文档后,发现该名词对我来说只不过是旧瓶装新酒罢了。
本文目录
- SAP UI5 Busy Dialog
- 使用代理模式( Proxy Pattern ) 提高 SAP UI5 大尺寸图片的加载体验
- SAP Spartacus Spinner 控件
- SAP Spartacus 幽灵设计
我对应用软件的 User Experience 即用户体验领域知之甚少。在 SAP 内部,有专门的用户体验设计师负责这个领域,因此我也不清楚 Skeleton / Ghost Design 准确的中文翻译是啥,姑且就直译成“幽灵设计”吧。
在我看来,无论是幽灵设计,还是之前 SAP UI5 提供的页面加载动画效果,都是改善用户使用体验的一种手段:提示用户当前页面正在加载后台数据,或是执行一些比较费时的操作。
SAP UI5 Busy Dialog
Jerry 从2014年开始使用 SAP UI5 进行 Fiori 开发,经历了 Fiori 1.0 到 2.0 的版本迭代。还记得处理的第一个 CRM Fiori 应用 My Opportunities 的 bug,症状就是修改了 Opportunity 数据之后,用户可以短时间内快速点击下图的 Save 按钮,从而产生多个到 CRM 后台的 OData 保存请求。
当时我的修复该问题的策略就是,在 Save 按钮点击之后,设置一个 Busy Dialog,让其锁住整个页面。这样,用户没有机会再点击 UI 进行任何操作了。直至 OData 请求在后台成功完成,或者收到错误提示,再关闭该 Busy Dialog,页面就能重新恢复可点击状态。
在 Fiori 1.0 时代,Busy Dialog 的外观是一个由5朵花瓣组成的花朵,具有不断旋转的动画效果。
可以通过这个视频查看运行时效果:
https://v.qq.com/x/page/y3225pbaqpa.html
Jerry 曾经写过一篇 SAP 社区博客:Fiori Busy Dialog – when is it opened and closed
该文章介绍了 SAP UI5 Busy Dialog 在 Fiori 应用中的使用场景。
一个典型的例子是,用户点击 Fiori Launchpad tile,跳转到某个具体的 Fiori 应用时,浏览器地址栏里的 url 发生变化, sap.ui.controller.doHashChange 会调用 BusyDialog.open 方法,绘制一个花瓣的动画效果:
如 Jerry 之前的文章 深入学习SAP UI5框架代码系列之二:UI5 控件的渲染器 所述,这个花瓣效果的实现 位于其渲染器 LoadingDialogRenderer 的方法 renderFioriFlower 内:
5片花瓣的视觉效果,通过5个 div 元素实现:
而花瓣旋转的动画效果,通过 div 元素 css 类的 animation 系列属性实现:
到了 Fiori 3.0 ,Jerry 发现 Busy Dialog 的外观,已经变成了三个大小不断变化的圆圈。
使用代理模式( Proxy Pattern ) 提高 SAP UI5 大尺寸图片的加载体验
我在 2015 年担任 一个德国 Fiori 客户上线的 Dev Angel 时,该客户有一个自开发需求:其产品主数据的配图动辄超过 10 MB,客户希望浏览器在成功加载这些尺寸巨大的图片之前,显示一些加载动画效果。待到图片完全加载结束时,再关闭加载动画,显示实际图片。
先看没有经过任何优化处理的情况下,如何在 SAP UI5 里使用 Image 控件显示一个 url 指向的图片:第10行调用 SAP UI5 控件 Image 实例的 setSrc 方法,加载 BIG_IMAGE 变量指向的图片。
再看我给客户推荐的基于图片代理的解决方案。
这是运行时的效果:
https://v.qq.com/x/page/n32257vdvui.html
这个方案实现源代码如下:
上图代码按照运行时执行的先后顺序,有4个关键点,分别用序号1~4表示:
-
第10行代码,创建一个新的 Image 实例,充当图片代理的角色。
-
第15行代码,UI5 应用里原始的 Image 实例,调用 setSrc 方法,传入的不是实际的大图片地址,而是一个存储在本地的,表示图片正在加载的 gif 文件( 客户自己准备,一个该企业 Logo 旋转的动画效果). 这样,用户打开页面时,首先映入眼帘的,是该本地 gif 文件 loading.gif 实现的不断旋转的动画效果。
-
第16行代码,将待加载大尺寸图片的 url 通过输入参数,传递给代理 Image 控件的 setSrc 方法。这会触发浏览器发起对大尺寸图片的加载。
-
第13行代码,当代理 Image 控件触发的大尺寸图片加载完成后,触发其 load 回调函数。该回调函数触发,说明大尺寸图片的数据已经完全加载到本地,此时在回调函数里,将大尺寸图片的 url 设置给原始 Image 控件的 src 属性,即可将该图片显示出来。
SAP Spartacus Spinner 控件
Spartacus 里的 Spinner 控件作用类似 SAP UI5 Busy Dialog,下面是一个例子:当第九行代码的组件属性 supportedDeliveryModes$.length 可用时,说明当前订单支持的商品递货模式的相关配置信息,已经从后台取到前台了,此时显示递货模式的选择页面;否则,则显示 ID 为 loading 标识的模板页面,里面只包含一个 Spinner 控件:
这个 Spinner 控件的外观及实现细节,请参考 Jerry 的视频:
https://v.qq.com/x/page/w3160fich85.html
最后来说说 SAP Spartacus 的幽灵设计。
Spartacus B2B 功能模块里,正常的 Cost Centers 列表显示如下:
在这些 Cost Center 的数据从后台取回来之前,页面显示如下,这种设计在 SAP Spartacus的帮助文档里,被称为 Skeleton 或者 Ghost Design:
这些在真实数据尚未从后台加载完毕之前,以“占位符”的方式显示在前台的灰色矩形条,绑定在 Angular Component 里的数据,就称为幽灵数据( Ghost Data ).
从Spartacus list.service.ts 的实现源代码能看出,幽灵数据就是一个 length 属性值为10的空数组。
在 Chrome 开发者工具里,能观察到这些幽灵数据具有对应的 CSS class,这使得它们具有灰色矩形的视觉外观:
Cost Center 表格显示的数据最终通过 list.service.ts 从 SAP Commerce Cloud 后台取出,取数逻辑通过 Angular 响应式编程库 RxJS的 pipe 方法驱动:第101行 switchMap 操作符里的箭头函数,输入参数 pagination 包含了去 Commerce Cloud 取数据使用的分页设置,函数体 this.load 发送 HTTP 请求,消费 Commerce Cloud 的 OCC API. 而第102行的 startWith操作符,语义上相当于给 pipe 驱动的 Observable 流赋上一个初始值,该初始值即为 length 属性为10的空数组。
这样,从运行时序来说,任何消费 getData 函数返回的 Observable 对象的 Angular UI 组件,都会先显示 startWith 设置的初始值,即幽灵数据。待从 Commerce Cloud 后台加载的真实数据返回给浏览器之后,组件自动刷新并显示这些真实的业务数据。
本文介绍了 Jerry 工作过的 SAP 产品里,当用户操作 UI 触发了某些后台数据加载时,为了提升用户体验而引入的一些页面效果的技术实现,希望对大家有所帮助,感谢阅读。
更多阅读
-
SAP UI5控件ID的生成逻辑
-
SAP UI5控件的多语言(国际化,Internationalization,i18n)支持的实现原理
-
XML视图里的button控件
-
button控件和它背后的DOM元素
更多Jerry的原创文章,尽在:"汪子熙":