当前位置: 首页 > news >正文

SAP学习笔记 - 开发27 - 前端Fiori开发 Routing and Navigation(路由和导航)

上一章讲了Remote OData Service(使用远端Odata服务) 相关的内容。

SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客

本章继续讲Fiori 开发的知识。

目录

1,Routing and Navigation(路由和导航)

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,总结:路由导航四步曲

  1. 配置:在 manifest.json 定义路由规则

  2. 初始化:在组件中调用 router.initialize()

  3. 导航:用 navTo() 触发路由跳转

  4. 响应:在目标视图通过 attachPatternMatched 处理参数

⚠️ 关键原则:路由应反映应用状态,而非视图结构。良好的路由设计是 SAP Fiori 应用可维护性的基石。

以上就是本篇的全部内容。

更多SAP顾问业务知识请点击下面目录链接或东京老树根的博客主页

https://blog.csdn.net/shi_ly/category_12216766.html

东京老树根-CSDN博客

相关文章:

  • STM32学习笔记:定时器(TIM)原理与应用(详解篇)
  • Linux进程(中)
  • AI大神吴恩达-提示词课程笔记
  • LLM 笔记:Speculative Decoding 投机采样
  • python并发编程
  • 【力扣】2434.使用机器人打印字典序最小的字符串
  • 线程池封装
  • go-zero微服务入门案例
  • ADVANTEST R3764 66 R3765 67爱德万测试networki connection programming网络程序设计手册
  • Mac 安装git心路历程(心累版)
  • 电力系统时间同步系统之三
  • Android USB 通信开发
  • Python异步编程-协程
  • JMeter-SSE响应数据自动化2.0
  • 在 Linux 中修改 Apache HTTP Server(httpd)默认端口的完整指南
  • 基于库博Cobot进行二次规则开发实训
  • VScode打开后一直显示正在重新激活终端 问题的解决方法
  • 【优选算法】C++滑动窗口
  • 【Go语言基础【13】】函数、闭包、方法
  • LVGL手势识别事件无上报问题处理记录
  • 网站是否wordpress/餐饮培训
  • 网站网址怎么做二维码/百度快照下载
  • 鲜花品牌网站建设/竞价托管公司排名
  • 用ps怎么做网站导航条/网站排名查询站长之家
  • 杭州做企业网站/市场营销手段13种手段
  • 义乌小商品市场进货渠道/如何进行关键词优化工作