使用webide 搭建路由routing并且使用官网控件
经过了一番折腾之后,大致对SAP UI5的架构有了一个系统的了解,PO主这里就不再循序渐进地探究其实现的原理,也不经过什么别的实现方法,直接从最优路线开始着手路由的配置问题
这里我没有使用eclipse而是webide,一个原因就是后者自动生成的项目架构更加地完全,并且现在已经基本可以理解文件的具体功能到底是什么,下面先简单地讲一下由WEBIDE生成后的项目里的各个子文件的功能和意义
- controller
从上往下来讲,第一个被创建的也就是controller,专门放置控制js文件的文件夹,不细说,遵循mvc以及index中的命名空间 - css
放置css文件的地方,既然官网已经为你创建了文件夹并且直接帮你在html中引入了这个文件,就不要在xml文件中试图自己加样式了,一切以分离为主 - i18n
这个文件类型我在上一篇博客也就是昨天之前都一直没有搞懂不知道是干嘛的,现在可以确定这是一个解决语言兼容性的文件,项目自动生成是只有头一个也就是i18n.properties文件,这个是默认的语言文件,在manifest.json存在时会有相关的配置,ui5框架会在浏览器启动时优先检测浏览器所使用的默认语言,这部分已经用使用不同默认语言的浏览器测试并且验证过了,在i18n之后跟上en或者是zh_CN就代表着当检测出的浏览器语言是英文或者是中文是,就可以跳过默认文件优先使用带尾缀的相应属性文件,当然里面的内容你可以自行编写,如果只用Ui5写国内的项目,也可以直接更改默认文件中绑定的属性语言,反正也不会有老外看,大不了再写个英文版就是了,我这里保险起见所以三个都建立了用于测试,不然webide本地服务启动之后控制台总是会报错有点烦。至于后面的尾缀自己查询相应的官方文档或者语言缩写自己试试,这里就不赘述了,我也是在别人博客看到的,没链接可贴,大家自力更生~ - localService
这个文件夹是用来放测试数据用的,模拟了mockdata的传递,在大神的博客中我发现他们用的是FakeRest.js来模拟发送请求并且阻拦jQuery的ajax请求达到模拟数据传递的效果,在用官方编辑器启动默认项目时会弹出一个messageText说mockdata正在运行,应该是下面的model.js默认引用了这里面的一个json文件并且模拟了请求,这方面我还没开始研究,今天的重点在路由,明天研究出来了再发一篇博客 - model
还没研究,估摸着跟上一个文件夹有千丝万缕的关系 - view
再提醒一次,官方都直接用xml文件了,并且,在官方控件网址中几乎所有的控件都只提供了xml的源码,所以大家三思而后行,放弃js view吧,这里贴出网址SAPUI5 Explored
我这里使用的是官网提供的侧边导航栏控件,大家注意,在编辑器中的layout editor功能里,很多控件是找不到的,官网能提供的更佳齐全,并且描述得已经很给力的,源码在samples选项下面的示例中,进入之后点击右上角其中一个按钮就可以进入源码页面,视图控件提供了view层以及controller层的源码,只需稍微改一下文件引入路径就好,用起来很方便,copy就行,拿回来慢慢改就好,css源码也有提供,但是改动的空间很大,值得一试。
官网不仅提供了源码,还提供了属性、事件、简介等,开个谷歌翻译就行,大致还是能看懂的。 - Component.js
这东西非常重要,在基础学习课程中,这个文件都作为路由和数据文件加载代码的配置文件,但是随着manifest.json文件的引入,这个文件的作用将会被削弱一些,不过功能还是不变的,只要容纳的是路由的初始化以及数据来源,相当于整个项目的入口文件了
多说一句,这文件千万不要改名!!!拒绝手残!!! - index.html
这个就不多说了,因为整个项目被生成的这么多文件给分摊掉了,所以在index中的script里所要写的代码将越来越少,这是一件好事。但是它主要的作用还是页面渲染的最后一个容器,尤其是在组件化开发之后,我在项目中使用了ui5的UIComponent依赖,实现了项目组件化开发,这个在下一个模块会讲解,index中更常用的是shell组件,官方称之为letter样式,可以让界面更美观,同时也可以确定整个页面所要呈现的宽高比等等
sap.ui.getCore().attachInit(function() {
new sap.m.Shell({
app: new sap.ui.core.ComponentContainer({
height : "100%",
name : "test1"
})
}).placeAt("content");
- manifest.json
这个东西更多的相当于是一个元数据描述文件,但在ui5项目中是一个入口文件的形式存在的,首先贴出源码
{
"_version": "1.1.0",
"sap.app": {
"_version": "1.1.0",
"id": "test1",
"type": "application",
"i18n": "i18n/i18n.properties",
"applicationVersion": {
"version": "1.0.0"
},
"title": "1",
"description": "1",
"resources": "resources.json",
"ach": "ach",
"sourceTemplate": {
"id": "servicecatalog.connectivityComponent",
"version": "0.0.0"
},
"dataSources": {
"mainService": {
"type": "OData",
"settings": {
"odataVersion": "2.0",
"localUri": "localService/metadata.xml" },
"uri": "localService/metadata.xml"
}
}
},
"sap.ui": {
"_version": "1.1.0",
"technology": "UI5",
"icons": {
"icon": "",
"favIcon": "",
"phone": "",
"phone@2": "",
"tablet": "",
"tablet@2": ""
},
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
},
"supportedThemes": ["sap_hcb", "sap_bluecrystal"]
},
"sap.ui5": {
"_version": "1.1.0",
"rootView": {
"viewName": "test1.view.App",
"type": "XML"
},
"routing": {
"config": {
"routerClass": "sap.m.routing.Router",
"viewType": "XML",
"viewPath": "test1.view",
"controlId": "app",
"controlAggregation": "pages",
"bypassed": {
"target": "notFound" }
},
"routes": [{
"pattern": "",
"name": "View1",
"target": "view1"
},
{
"pattern":"page",
"name": "Page",
"target": "page"
}
],
"targets": {
"view1": {
"viewName": "View1",
"viewLevel": 1 },
"page":{
"viewName": "Page",
"viewLevel": 2 }
}
},
"dependencies": {
"minUI5Version": "1.30.0",
"libs": {
"sap.ui.core": {},
"sap.m": {},
"sap.ui.layout": {}
}
},
"contentDensities": {
"compact": true,
"cozy": true
},
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "test1.i18n.i18n" }
},
"": {
"dataSource": "mainService"
}
},
"resources": {
"css": [{
"uri": "css/style.css"
}]
}
}
}
- sap.app 这里面最吸引人的就是i18n的路径配置,当项目启动时找不到浏览器默认语言的i18n文件,就会自动根据这个路径来找默认的文件了
- dataSources 顾名思义,数据的路径,这个不细讲,明天说
- sap.ui5 这里面的配置非常重要,也关系到了路由的问题,这里重点说一下。在webide刚生成项目的时候,其实就已经是默认使用组件化开发了,因为在这里面已经定义了root view并且制定了其类型,不过后面的routing选项是我自己加上去的,作为子路由描述,接下来重点讲一下routing的配置
- config
"config": {
"routerClass": "sap.m.routing.Router",
"viewType": "XML",
"viewPath": "test1.view",
"controlId": "app",
"controlAggregation": "pages",
"bypassed": {
"target": "notFound"
}
大家仔细看我的文件列表,在我view层的最上方我指定了一个app.view作为我的根组件去承载其他的组件,所以这里的controId是app
app源码
<core:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m"
xmlns:html="http://www.w3.org/1999/xhtml" displayBlock="true">
<App id="app"/>
</core:View>
在这个配置项中指定了依赖,类型,视图的路径,视图标签以及路由错误时所要引出的页面not found
- routes
"routes": [{
"pattern": "",
"name": "View1",
"target": "view1"
},
{
"pattern":"page",
"name": "Page",
"target": "page"
}
],
这个配置项是以一个数组的形式存在的,目前没有尝试这种写法是父子路由才这么写还是一股脑都扔进这个数组里,以后有空再说,在这里,我把首先被加载的页面定义为View1,这也是我的view层中视图文件名,我使用了首字母大写来区分,下面的target配置项我使用了小写,注意,第一个被加载的页面貌似是在pattern属性中保持空值的,但是被跳转的页面pattern中是需要放置一个值的,写啥貌似无所谓,我这里就保持了和名字一样的字符串来区分
- targets
"targets": {
"view1": {
"viewName": "View1",
"viewLevel": 1
},
"page":{
"viewName": "Page",
"viewLevel": 2
}
}
这个配置项中区分了层级关系,但是父子路由的概念没有很好地被区分开,这个暂且不研究,viewName相当于每个视图文件的ID,这个就不做讲解了,下面那个应该就是等级的意思,数字越小等级越大。
现在manifest.json文件就算是配置完成了,然后去配置Component.js文件,下面直接附上源码
sap.ui.define([
"sap/ui/core/UIComponent",
"sap/ui/Device",
"test1/model/models"
], function(UIComponent, Device, models) {
"use strict";
return UIComponent.extend("test1.Component", {
metadata: {
manifest: "json"
},
/**
* The component is initialized by UI5 automatically during the startup of the app and calls the init method once.
* @public
* @override
*/
init: function() {
// call the base component's init function
UIComponent.prototype.init.apply(this, arguments);
this.getRouter().initialize();
// set the device model
this.setModel(models.createDeviceModel(), "device");
}
});
});
最后去View1.view.xml中添加事件,官网提供的是itemSelect事件,不过这个好像点击整个导航栏都会触发,如果要求子项目应该还要遍历传参,以后再说,先用着~
然后去相应的controller文件中获取路由并且navTo到我们想要去的Page页面
sap.ui.define([
'jquery.sap.global',
'sap/ui/core/mvc/Controller',
'sap/m/Popover',
'sap/m/Button',
"sap/ui/core/UIComponent",
'sap/m/MessageToast'
], function(jQuery, Controller, Popover, Button , UIComponent ,MessageToast) {
"use strict";
Controller.extend("test1.controller.View1", {
onInit: function () {
},
onCollapseExapandPress: function () {
var sideNavigation = this.getView().byId('sideNavigation');
var expanded = !sideNavigation.getExpanded();
sideNavigation.setExpanded(expanded);
},
onListPress: function() {
var oRouter = UIComponent.getRouterFor(this);
MessageToast.show(oRouter+" Pressed"); //方法被触发了
oRouter.navTo("Page",{},true);
}
});
return Controller;
});
这里温馨提示一下,由于框架的问题,大家在前端开发时经常会使用alert或者是console.log来打印出相应的值来排查错误,但是这在UI5中并不可行,在官方IDE中会被eslint检测并报错,而且没有效果,所以我建议使用它们官方的messageText来直接弹出一个消息盒子,这样就可以实现和console一样的效果了,不然这个每次控制台的报错提示都这么坑我真的想骂人。
项目源码