SAP学习笔记 - 开发27 - 前端Fiori开发 Routing and Navigation(路由和导航)
上一章讲了Remote OData Service(使用远端Odata服务) 相关的内容。
SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客
本章继续讲Fiori 开发的知识。
目录
1),manifest.json
2),Component.js
3),Overview.view.xml
4),App.view.xml
5),Detail.view.xml
6),i18n.properties
7),InvoiceList.view.xml
8),InvoiceList.controller.js
9),运行看效果
2,总结
2-1,SAP Fiori 路由与导航核心概念
1),路由的本质
2),核心组件
2-2、路由配置详解 (manifest.json)
2-3、路由生命周期与关键方法
1),初始化路由
2),触发导航
3),路由事件监听
2-4、高级导航模式
1),嵌套路由
2),路由参数类型
3),路由中间件
2-5、最佳实践
1),URL 设计原则
2),视图生命周期
3),错误处理
4),移动端优化
2-6、Fiori Elements 特殊处理
2-7,路由 vs 直接视图加载
2-8,常见问题解决方案
1),路由不生效
2),参数获取失败
3),视图缓存问题
4),返回按钮控制
2-9,总结:路由导航四步曲
下面是详细内容。
1,Routing and Navigation(路由和导航)
SAPUI5 SDK - Demo Kit
概念大家都懂,咱们直接看Fiori里面怎么实现的。
1),manifest.json
{"_version": "1.65.0","sap.app": {"id": "ui5.walkthrough","i18n": "i18n/i18n.properties","title": "{{appTitle}}","description": "{{appDescription}}","type": "application","applicationVersion": {"version": "1.0.0"},"dataSources": {"invoiceRemote": {"uri": "V2/Northwind/Northwind.svc/","type": "OData","settings": {"odataVersion": "2.0"}}}},"sap.ui": {"technology": "UI5","deviceTypes": {"desktop": true,"tablet": true,"phone": true}},"sap.ui5": {"dependencies": {"minUI5Version": "1.108.0","libs": {"sap.ui.core": {},"sap.m": {}}},"models": {"i18n": {"type": "sap.ui.model.resource.ResourceModel","settings": {"bundleName": "ui5.walkthrough.i18n.i18n","supportedLocales": [""],"fallbackLocale": ""}},"invoice": {"dataSource": "invoiceRemote"}},"rootView": {"viewName": "ui5.walkthrough.view.App","type": "XML","id": "app"},"resources": {"css": [{"uri": "css/style.css"}]},"routing": {"config": {"routerClass": "sap.m.routing.Router","type": "View","viewType": "XML","path": "ui5.walkthrough.view","controlId": "app","controlAggregation": "pages"},"routes": [{"pattern": "","name": "overview","target": "overview"},{"pattern": "detail","name": "detail","target": "detail"}],"targets": {"overview": {"id": "overview","name": "Overview"},"detail": {"id": "detail","name": "Detail"}}}}
}
这代码是越来越多了哈,这改了哪里了呢?
基本上就是设定了路由处理模块,以及定义了本app里有几个路由:
"sap.ui5": {
。。。
"routing": {
"config": {
"routerClass": "sap.m.routing.Router", ==》设定路由处理模块
"type": "View",
"viewType": "XML",
"path": "ui5.walkthrough.view",
"controlId": "app",
"controlAggregation": "pages"
},
"routes": [ ==》设定路由一览,咱这里有2个路由,默认是overview,还有一个detail 路由
{
"pattern": "",
"name": "overview",
"target": "overview"
},
{
"pattern": "detail",
"name": "detail",
"target": "detail"
}
],
"targets": {
"overview": {
"id": "overview",
"name": "Overview"
},
"detail": {
"id": "detail",
"name": "Detail"
}
}
}
}
2),Component.js
sap.ui.define(["sap/ui/core/UIComponent","sap/ui/model/json/JSONModel"
], (UIComponent, JSONModel) => {"use strict";return UIComponent.extend("ui5.walkthrough.Component", {metadata : {interfaces: ["sap.ui.core.IAsyncContentCreation"],manifest: "json"},init() {// call the init function of the parentUIComponent.prototype.init.apply(this, arguments);// set data modelconst oData = {recipient : {name : "World"}};const oModel = new JSONModel(oData);this.setModel(oModel);// create the views based on the url/hashthis.getRouter().initialize();}});
});
注释有点儿怪哈,应该是把上面manifest里面定义的路由给 load 一下,其实SAP就干了得了呗
// create the views based on the url/hash
this.getRouter().initialize();
3),Overview.view.xml
<mvc:ViewcontrollerName="ui5.walkthrough.controller.App"xmlns="sap.m"xmlns:mvc="sap.ui.core.mvc"displayBlock="true"><Page title="{i18n>homePageTitle}"><content><mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel" /><mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList" /></content></Page>
</mvc:View>
这个代码看着是不是和 App.view.xml 里的一样,对,就是把那里的代码拿过来了
对比一下App.view.xml,构造略有不同,代码基本是一样的吧
<mvc:ViewcontrollerName="ui5.walkthrough.controller.App"xmlns="sap.m"xmlns:mvc="sap.ui.core.mvc"displayBlock="true"><Shell><App class="myAppDemoWT"><pages><Page title="{i18n>homePageTitle}"><content><mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/><mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/></content></Page></pages></App></Shell>
</mvc:View>
4),App.view.xml
App view 里面的代码修改一下
<mvc:ViewcontrollerName="ui5.walkthrough.controller.App"xmlns="sap.m"xmlns:mvc="sap.ui.core.mvc"displayBlock="true"><Shell><Appclass="myAppDemoWT"id="app"/></Shell>
</mvc:View>
这回只要通过一个 id = “app"就可以指定要显示的view 了,那这个 ”app"是谁呢?
就是咱们上面定义的 manifest.json 里面的 路由(routing)里的 controlId:"app" 那段儿
5),Detail.view.xml
<mvc:Viewxmlns="sap.m"xmlns:mvc="sap.ui.core.mvc"><Pagetitle="{i18n>detailPageTitle}"><ObjectHeader title="Invoice"/></Page>
</mvc:View>
这就是Detail view,其实里面就是一行字儿
6),i18n.properties
# App Descriptor
appTitle=Hello World
appDescription=A simple walkthrough app that explains the most important concepts of SAPUI5# Hello Panel
showHelloButtonText=Say Hello
helloMsg=Hello {0}
homePageTitle=Walkthrough
helloPanelTitle=Hello World
openDialogButtonText=Say Hello With Dialog
dialogCloseButtonText=Ok# Invoice List
invoiceListTitle=Invoices
invoiceStatusA=New
invoiceStatusB=In Progress
invoiceStatusC=Done# Detail Page
detailPageTitle=Walkthrough - Details
一行字儿也不能马虎😓,从properties 文件里取
7),InvoiceList.view.xml
<mvc:ViewcontrollerName="ui5.walkthrough.controller.InvoiceList"xmlns="sap.m"xmlns:core="sap.ui.core"xmlns:mvc="sap.ui.core.mvc"><Listid="invoiceList"headerText="{i18n>invoiceListTitle}"class="sapUiResponsiveMargin"width="auto"items="{path : 'invoice>/Invoices',sorter : {path : 'ShipperName',group : true}}"><headerToolbar><Toolbar><Title text="{i18n>invoiceListTitle}"/><ToolbarSpacer/><SearchField width="50%" search=".onFilterInvoices"/></Toolbar></headerToolbar><items><ObjectListItemcore:require="{Currency: 'sap/ui/model/type/Currency'}"title="{invoice>Quantity} x {invoice>ProductName}"intro="{invoice>ShipperName}"number="{parts: ['invoice>ExtendedPrice','view>/currency'],type: 'Currency',formatOptions: {showMeasure: false}}"numberUnit="{view>/currency}"numberState="{= ${invoice>ExtendedPrice} > 50 ? 'Error' : 'Success' }"type="Navigation"press=".onPress"><firstStatus><ObjectStatuscore:require="{Formatter: 'ui5/walkthrough/model/formatter'}"text="{path: 'invoice>Status',formatter: 'Formatter.statusText.bind($controller)'}"icon="sap-icon://accept"/></firstStatus></ObjectListItem></items></List>
</mvc:View>
1,这里加了下面两行代码
type="Navigation" =》这行是说把 这个 ObjectListItem(行项目)给变成可点击的,显示为小手
press=".onPress" =》这是点击事件处理函数
8),InvoiceList.controller.js
sap.ui.define(["sap/ui/core/mvc/Controller","sap/ui/model/json/JSONModel","sap/ui/model/Filter","sap/ui/model/FilterOperator"
], (Controller, JSONModel, Filter, FilterOperator) => {"use strict";return Controller.extend("ui5.walkthrough.controller.InvoiceList", { onInit() {const oViewModel = new JSONModel({currency: "EUR"});this.getView().setModel(oViewModel, "view");},onFilterInvoices(oEvent) {// build filter arrayconst aFilter = [];const sQuery = oEvent.getParameter("query");if (sQuery) {aFilter.push(new Filter({filters: [new Filter("ProductName", FilterOperator.Contains, sQuery),new Filter("ShipperName", FilterOperator.Contains, sQuery)],and: false // 表示“或”关系(任一字段匹配即可)}));}// filter bindingconst oList = this.byId("invoiceList");const oBinding = oList.getBinding("items");oBinding.filter(aFilter);},onPress() {const oRouter = this.getOwnerComponent().getRouter();oRouter.navTo("detail");}});
});
1,这个就是事件处理代码
onPress() {
const oRouter = this.getOwnerComponent().getRouter(); =》取得manifest 里面定义的路由
oRouter.navTo("detail"); =》找到 detail 名的那个路由,然后用 navTo 函数给导航(迁移)过去
}
9),运行看效果
鼠标移动到行项目上的时候,会显示为小手
然后右侧也会有 > ,意思是点了就会迁移过去
点一下之后,就会迁移过去,这是 detail view
2,总结
以下内容是在Deepseek中查询之后整理而成。
整理完之后,我也是一脸懵,所以即使看不懂也没关系,以后慢慢理解😄,要是你一看就懂,NB
2-1,SAP Fiori 路由与导航核心概念
1),路由的本质
-
URL ↔ 应用状态映射:将浏览器 URL 路径映射到应用的特定视图和状态
-
深层链接:允许直接通过 URL 访问应用内的特定页面(如书签分享)
-
历史管理:自动处理浏览器前进/后退按钮行为
2),核心组件
组件 | 作用 | 关键配置位置 |
---|---|---|
路由器 (Router) | 控制导航逻辑 | Component.js |
路由配置 (Routes) | 定义 URL 模式与视图映射 | manifest.json |
目标 (Targets) | 声明视图/组件加载方式 | manifest.json |
哈希前缀 (hashPrefix) | URL 中 # 后的前缀(默认空) | 路由初始化配置 |
2-2、路由配置详解 (manifest.json)
json
"routing": {"config": {"routerClass": "sap.m.routing.Router","controlId": "app", // 容器控件ID"controlAggregation": "pages", // 视图加载位置"transition": "slide", // 视图切换动画"async": true // 异步视图加载},"routes": [{"pattern": "", // 默认路径"name": "home", // 路由名称"target": "home" // 目标名称},{"pattern": "products/{id}", // 带参数路径"name": "productDetail","target": "productDetail"}],"targets": {"home": {"viewName": "Home", // 视图名称"viewLevel": 1 // 视图层级(用于返回按钮)},"productDetail": {"viewName": "ProductDetail","viewLevel": 2}}
}
2-3、路由生命周期与关键方法
1),初始化路由
javascript
// Component.js
sap.ui.define(["sap/ui/core/UIComponent"
], function(UIComponent) {return UIComponent.extend("my.Component", {init: function() {UIComponent.prototype.init.apply(this, arguments);this.getRouter().initialize(); // 关键初始化!}});
});
2),触发导航
javascript
// 控制器中导航
this.getOwnerComponent().getRouter().navTo("productDetail", {id: productId // 传递路径参数
}, true); // 第三个参数:是否替换历史记录
3),路由事件监听
javascript
// 在目标视图的控制器中
onInit: function() {const router = this.getOwnerComponent().getRouter();router.getRoute("productDetail").attachPatternMatched(this._onRouteMatched, this);
},
_onRouteMatched: function(event) {const args = event.getParameter("arguments");const productId = args.id; // 获取URL参数this.loadProductData(productId);
}
2-4、高级导航模式
1),嵌套路由
json
"routes": [{"pattern": "users/{userID}","name": "userMain","target": "userMaster"},{"pattern": "users/{userID}/orders/{orderID}","name": "orderDetail","target": ["userMaster", "orderDetail"] // 多目标}
]
2),路由参数类型
javascript
// 定义参数约束
pattern: "products/{id:int}" // 只匹配整数ID
3),路由中间件
javascript
// 在路由匹配前执行逻辑
router.getRoute("securePage").attachBeforeMatched(function() {if (!user.isAuthenticated()) {router.navTo("login");return false; // 阻止路由匹配}
});
2-5、最佳实践
1),URL 设计原则
- 语义化路径:/products/123 优于 /page?type=prod&id=123
- 扁平化结构:最多 2-3 级嵌套
- 参数最小化:避免长查询字符串
2),视图生命周期
- 使用 onPatternMatched 替代 onInit 加载数据
- 在 onExit 中清理事件监听
3),错误处理
Javascript
router.attachBypassed(function(event) {console.error("No route found:", event.getParameter("hash"));
});
4),移动端优化
- 使用 viewLevel 控制返回按钮行为
- 响应式路由:平板/手机不同导航模式
2-6、Fiori Elements 特殊处理
在 Smart Templates 中:
- 列表报告 → 对象页 导航自动配置
- 通过 manifest.json 的 navigation 部分定义
json
"navigation": {"detail": {"route": "ObjectPageRoute","parameters": {"key": "{key}"}}
}
2-7,路由 vs 直接视图加载
方式 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
路由导航 | 多视图应用、深层链接 | 状态可回溯、URL 共享 | 配置较复杂 |
直接加载 | 简单弹窗、一次性视图 | 编码简单、快速实现 | 无法书签分享 |
2-8,常见问题解决方案
1),路由不生效
- 检查 manifest.json 是否被正确加载
- 确认 Component.prototype.init 中调用了 initialize()
- 验证路由名称拼写一致性
2),参数获取失败
- 确保 attachPatternMatched 在控制器初始化时注册
- 检查 URL 模式与参数名匹配(区分大小写)
3),视图缓存问题
javascript
targets: {"detail": {"viewId": "uniqueDetailView", // 强制创建新实例"viewName": "Detail"}}
4),返回按钮控制
javascript
// 自定义返回逻辑onNavBack: function() {const history = sap.ui.core.routing.History.getInstance();const prevHash = history.getPreviousHash();if (prevHash) window.history.go(-1);else this.getRouter().navTo("home");}
2-9,总结:路由导航四步曲
-
配置:在
manifest.json
定义路由规则 -
初始化:在组件中调用
router.initialize()
-
导航:用
navTo()
触发路由跳转 -
响应:在目标视图通过
attachPatternMatched
处理参数
⚠️ 关键原则:路由应反映应用状态,而非视图结构。良好的路由设计是 SAP Fiori 应用可维护性的基石。
以上就是本篇的全部内容。
更多SAP顾问业务知识请点击下面目录链接或东京老树根的博客主页
https://blog.csdn.net/shi_ly/category_12216766.html
东京老树根-CSDN博客