這是 Jerry 2021 年的第 68 篇文章,也是汪子熙公眾號總共第 345 篇原創文章。
Jerry 之前的文章,談談 SAP 產品 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 Cloud for Customer頁面嵌入自定義UI 介紹的場景,比如我們可以把第三方網站或者自開發的部署在 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 組件(參考我的文章:談談 SAP 產品 UI 開發中的組件概念)和容器組件的概念和開發方式,就足以勝任大多數場合下的工作需求了。
Jerry 后續將帶來更多關於 SAP UI 開發技術的分享,敬請期待。
更多閱讀
更多Jerry的原創文章,盡在:"汪子熙":