头图

笔者在掘金社区上已经发布了一些技术文章,记录了自己工作于企业级前端应用几年以来积累的一些项目经验和教训。

之前的文章关于企业级 Web 应用搜索引擎优化 Search Engine Optimization 的一些工作经验分享已经提到,所谓企业级前端应用,是指为大型企业或组织开发的前端应用,这些应用具有超过一般 2C 软件的技术复杂度,高度定制化和可扩展性,因为企业级前端应用程序,通常需要满足企业特定的业务需求和技术要求,因此除了实现业务需求之外,还必须具备强大的性能、可扩展性、安全性和可维护性。在企业级前端开发中,开发者需要面对大规模数据处理、复杂的业务逻辑、多模块协同工作等挑战。

企业级 Web 应用的 UI,当然不可能像我们大学校园里完成课程作业时开发的那种玩具式的 UI 那么简单。为了最大限度地提高生产效率,企业级 Web 应用的 UI 必然追求高度的组件化。

笔者这篇文章给大家分享我曾经从事过的几款 SAP 旗下的企业级 Web 应用中 UI 组件的设计和实现思路。

无论基于何等开发技术的 SAP 产品 UI,其呈现在最终用户面前的视觉效果,都是通过若干逻辑意义上的组件(Component)实现的。这些逻辑意义上的组件,代表了 SAP 产品提供给最终用户交互功能的细粒度的封装,比如查询订单的界面,和创建订单的界面,开发时通常放置于两个不同的组件内实现。

这些 UI 组件通常都包含模型层,视图层和控制器层,通过开源或者 SAP 自研的 UI 框架彼此交互,协同工作。

不少 SAP 产品的 UI 开发,组件的定义和边界非常清晰,比如 SAP UI5 里的 Component.js, SAP ABAP Webdynpro 和 WebClient UI 的 Component,SAP Commerce Cloud Accelerator UI 里的 JSP Component 和 Spartacus UI 里的 Angular Component.这些产品的 UI 开发工作,主要就是进行这些 Component 的代码编写。

下图所示的 SAP Cloud for Customer UI Designer 里这些类型各异的 UI 模型,如 OWL,QAF, FS 等等,更是典型的 UI 组件的例子。

另外一些早期的 SAP 产品,比如运行在 SAPGUI 里的 SAP ERP,其界面采用 ABAP Dynpro 实现,后者没有明确提出 UI 组件的概念。但 ABAP Dynpro Screen 和 PAI/PBO 逻辑组合在一起,从设计和功能角度来说,也形成了一个逻辑意义上的 UI 组件。

本文通过一系列 SAP 产品 UI 为例,介绍 SAP 产品 UI 开发领域里另一种重要的组件类型,我称其为容器组件。

同前文描述的包含了具体界面和业务功能的 UI 组件相比,容器组件自身并不存在呈现给最终用户的界面,而是单纯地充当容器的角色,它们是容纳其他 UI 组件的组件。部分容器组件可能支持一些简单的控制逻辑编写,运行时能够根据开发人员指定的条件,动态地决定应该显示其包含的哪些 UI 组件。

下面通过 Jerry 参与过的一些 SAP 产品 UI 开发工作中的具体例子,来介绍 SAP UI 容器组件的概念和作用。

SAP WebClient UI

下图是基于 SAP WebClient UI 开发的 SAP CRM 产品明细页面。红色区域代表一个个普通的 UI 组件,绿色区域是一个容器组件,后者决定运行时,到底应该显示其容纳的哪些 UI 组件。

启动事物码 BSP_WD_CMPWB, 打开 UI 组件开发环境,查看 ID 为 PRD01OV 的产品明细页面的容器组件。下图是该容器组件容纳的 UI 组件列表。运行时产品明细页面显示的实际内容,是这个列表的子集。

SAP Cloud for Customer / SAP Business ByDesign

SAP Cloud for Customer 同 SAP CRM 一样,都借助了工作中心(Work Center)和工作中心视图(Work Center View)的概念来实现权限管控。用户只能看到分配给其的工作中心视图包含的具体界面。对开发人员来说,SAP CRM 的工作中心只是配置表里的一些条目,而 SAP Cloud for Customer 里的工作中心和工作中心视图,成为开发工具里能实实在在看到和编辑的 UI 模型。一个工作中心包含若干个工作中心视图,下图是一个例子:

点开上图所示的 Sales Order 工作中心视图,可以看到该工作中心视图包含了一个 OWL Component:

OWL 是 Object Work List 的缩写,即下图所示的给最终用户提供搜索界面的 UI 组件。这体现了 SAP 产品关于 Transaction 处理的一贯思路:客户一般都是从 SAP 产品 UI 提供的事务数据搜索页面开始,从搜索结果里选中一条,浏览明细页面。SAP Cloud for Customer 和 SAP Business ByDesign 的搜索页面,就是由类型为 OWL 的 UI 组件实现的,而这些 OWL 组件,又被放置到工作中心视图这个容器组件内。

SAP Cloud for Customer 还存在另一类使用广泛,功能强大的容器组件 EC Component,即 Embedded Component,嵌入式组件。EC Component 作为容器控件,本身能够容纳其他的 UI 组件,同时其本身能够以紧耦合和松耦合的方式,嵌入到另一个父组件中,通过多种方式使其内部容纳的 UI Component 同嵌入的父组件之间进行数据传递和通信。

借助 SAP C4C 的 Mashup 技术,EC Component 无论是在 SAP C4C 标准开发,还是合作伙伴二次开发领域,都有着广泛的用途。比如下图所示 SAP C4C 的地图集成功能:

我们可以把第三方网站或者自开发的部署在 SAP BTP 平台上的页面,通过 EC Component 嵌入到 SAP C4C 标准 UI 上去。

SAP 电商云 Spartacus UI

作为基于无头电商(Headless Commerce)架构解决方案的代表之一,SAP Commerce Cloud Spartacus UI 页面的展示,采取纯 CMS 驱动的思路来完成。

CMS(Content Management System)管理员,在 SAP Commerce Cloud Backoffice 里定义电商云前台需要显示的页面内容。这些页面内容定义,通过暴露成 OCC(Omni Commerce Connect) API 的方式,提供给 SAP Spartacus UI 消费。后者拿到需要显示的页面内容之后,负责具体的视觉效果(Visual Effect)渲染。

以 SAP 电商云的主页 homepage 为例,CMS 管理员在 homepage 里,维护该页面容纳的 Content Slots(内容插槽)。 一个页面可以容纳多个内容插槽,每个页面插槽对应屏幕一个区域。

这些内容插槽,按照显示内容,把 homepage 划分成若干个区域,比如 HeaderSlot,FooterSlot,SiteLogoSlot, Section1Slot,Section2Slot 等等。

每个内容插槽里能够放置一到多个 CMS Component,这里的 CMS Component 起的是占位符的作用—— CMS 管理员不关心每个 CMS Component 具体显示的视觉效果,甚至不关心这些 CMS Component,到底是由 JSP 还是用 Angular 来实现。

下图展示的是 Section1Slot 这个内容插槽,放置的两个 CMS Component 的名称。SAP 电商云 Accelerator UI 和 Spartacus UI,会分别使用 JSP Component 和 Angular Component 技术实现这些 CMS Component. 大家可以把下图 Backoffice 所示的放置在内容插槽中的 CMS Component,与其和在 Accelerator UI 和 Spartacus UI 中的 Component 之间的关系,类比成面向对象编程中接口和其具体实现类的关系。

上图描述的 Section1Slot 内容插槽和名为 Electronics Homepage Splash Banner Component 的 CMS Component 的包含关系,能够在如下的 OCC API 调用结果中反映出来:

Spartacus 解析上图 API 响应结果,拿到 name 属性为 Electronics Homepage Splash Banner Component 的组件,得知其 typeCode 为 SimpleResponsiveBannerComponent,然后在其维护的映射表里,查找到该 CMS Component 对应的 Angular Component 名称为 BannerComponent,于是就会渲染 BannerComponent 对应的模板文件。

下图是 SAP 电商云 Spartacus 页面的 homepage 渲染完毕的界面,其中黄色高亮区域就是内容插槽 Section1Slot 的起始位置,而两片绿色高亮区域,分别就是该内容插槽里放置的两个 CMS Component,对应到 Spartacus UI 里通过 Angular Component 形式渲染的起始位置。

虽然从最终用户的视角出发,觉察不到容器组件的存在,但对于 Spartacus UI 的标准开发人员和需要进行二次开发的合作伙伴来说,Spartacus UI 的容器组件是一个比较重要的概念。

SAP Spartacus UI 的入口页面,实现代码位于 storefront.component.html 模板文件。不到30行的代码,把这个基于 Angular 的 UI 界面,划分成了 header,main 和 footer 三大区域。

在运行时,客户访问任何 Spartacus UI,我们都将会将渲染出的 HTML 原生代码对应的 DOM 元素,放置在上图第 21 行 Angular 路由指令 router-outlet 的正下方,成为其兄弟节点。

以客户访问 homepage 的场景为例,最后生成的 HTML 源代码如下:

上图是理解 SAP 电商云 Spartacus UI 运行时渲染原理的关键所在,展示了 SAP Spartacus 两个重要的容器组件。

标注2 显示的 cx-page-layout, 以及其若干个子节点 cx-page-slot, 分别对应了 SAP Spartacus 两大容器组件 PageLayoutComponent 和 PageSlotComponent 的选择器。

从 PageLayoutComponent 容器组件的模板文件实现能够看出,每个 PageLayoutComponent 的实例,实际就是 CMS 管理员在 Backoffice 里维护的一个 Page 在 Angular 端的具体呈现形式。

当最终用户访问 SAP 电商云 Spartacus UI 时,后者调用 OCC API,将对应 Page 在 Backoffice CMS 中的模型数据取回来,该 Page 分配的内容插槽信息,存储在上图第 16 行的 slots$ 变量里。PageLayoutComponent 使用 Angular 结构型指令 *ngFor, 遍历这个 slots$ 变量,将每条内容插槽记录的数据,传递给另一个容器组件 PageSlotComponent,其选择器为第 15 行所示的 cx-page-slot.

PageSlotComponent 根据 PageLayoutComponent 传入的内容插槽信息,解析出该插槽分配的 CMS Components 信息。因为单个内容插槽可以分配多个 CMS Components,因此在第 10 行同样使用结构型指令 *ngFor, 遍历该内容插槽需要显示的每一个 CMS 组件信息,将该信息传递给第 19 行我们团队自定义的 Angular 指令 cxComponentWrapper.

这个带有我们部门名称前缀 cx - Customer Experience 的自定义指令,会根据传入的 CMS Component 类型,解析出对应的 Angular Component 元数据,然后调用 Angular Component creation API,动态创建 Component 实例并触发渲染流程。

采取这种 CMS 驱动的设计思路,通过 PayLayoutComponent 和 PageSlotComponent 两大容器组件的配合,无论 CMS 管理员在 Backoffice 对一个 Page 待显示的内容进行何种修改,Spartacus UI 端的代码均能够自动应对这些修改,做到以不变应万变。

总结

本文概述了 SAP WebClient UI,SAP Cloud for Customer 和 SAP Commerce Cloud Spartacus UI 中容器组件的设计和运行原理。个人认为,学习 SAP 某个产品的 UI 开发,只要掌握了其普通 UI 组件和容器组件的概念和开发方式,就足以胜任大多数场合下的工作需求了。


注销
1k 声望1.6k 粉丝

invalid