深入 AngularUI Router
翻译:深入 AngularUI Router
原文地址:http://www.ng-newsletter.com/posts/angular-ui-router.html
ui-router: https://angular-ui.github.io/ui-router/site/#/api/ui.router
ui-router 是 AngularUI 库提供的特别有用的一个部分,是一个通过提供状态机机制,而不是简单的 URL 来组织我们的界面的路由框架。
这个库提供了针对视图的众多的额外控制,我们可以创建嵌套的视图,在单个页面使用多个视图,多个视图来控制单个视图,还有更多特性。对于更加精细的控制和更为复杂的应用,ui-router 是非常棒的工具。
ui-router 从状态着手来管理路由,它将应用视为多个状态的组合,通过状态的切换进行路由。
- 一个状态可以对应一个页面地址,通过特定的地址到达应用的特定状态。
- 通过状态的 controller、template 和 views 来管理特定状态的 UI 和行为
- 通过嵌套视图来解决页面中重复出现的内容。
Installation
安装 ui-router,既可以直接下载发布版本,也可以通过 bower 来获取。
$ bower install angular-ui-router --save
然后,需要在页面中进入这个库,当然要先加载 angular 库。
<script type="text/javascript" src="angular-ui-router.js"></script>
在 angular 中注入 ui.router.
angular.module('myApp', ['ui.router'])
不像 angular 内置的 ngRoute, ui-router 可以嵌套视图,它是基于状态,而不 URL 的。
也不像 ngRoute 使用 ng-view 指令,在 ui-router 中,我们使用 ui-view 指令。
当在 ui-router 中考虑路由和状态的关系时,我们主要关注应用的什么状态对应应用的什么路由。
<div ng-controller="DemoController"><div ui-view></div> </div>
类似 ngRoute, 对于给定的状态,模板中的内容将会填充到 <div ui-view></div> 元素,每个模板还可以包含自己的 ui-view ,这就是我们可以支持嵌套路径的原因。
定义路径的时候,我们使用 .config 方法,像通常一样,但是使用 $stateProvider 来替换 $routeProvider。
![](/assets/blank.gif)
.config(function($stateProvider, $urlRouterProvider) {$stateProvider.state('start', {url: '/start',templateUrl: 'partials/start.html'}) });
![](/assets/blank.gif)
这样,我们;定义了名为 start 的状态,传递的对象定义了状态配置信息,或者称为 stateConfig,类似于路由配置对象,我们通过它配置状态信息。
template, templateUrl, templateProvider
可以使用下面三种之一的方式来定义视图使用的模板:
- template, 字符串方式的模板内容,或者是一个返回 HTML 的函数
- templateUrl, 模板的路径,或者返回模板路径的函数
- templateProvider, 返回 HTML 内容的函数
例如
$stateProvider.state('home', {template: '<h1>Hello {{ name }}</h1>' });
Controller
类似于 ngRoute,我们既可以通过控制器的名字来关联一个预定义的控制器,也可以直接创建一个控制器函数来处理。
如果没有对应的模板定义,控制器对象就不会被创建。
Resolve
使用 resolve 功能,我们可以准备一组用来注入到控制器中的依赖对象。在 ngRoute 中,resolve 可以在路由实际渲染之前解决掉 promise
resolve 选项提供一个对象,对象中的 key 就是准备注入 controller 的依赖名称,值则是创建对象的工厂。
如果是一个串,就试图用这个串来匹配当前已经注册的服务名称,如果是一个函数,执行这个函数,返回的值就是依赖。如果函数返回一个 promise,在控制器被实例化之前,将会被 resolved,返回的值被注入到 controller 中。
![](/assets/blank.gif)
$stateProvider.state('home', {resolve: {// This will return immediately as the // result is not a promiseperson: function() {return {name: "Ari",email: "ari@fullstack.io"}},// This function returns a promise, therefore// it will be resolved before the controller// is instantiatedcurrentDetails: function($http) {return $http({method: 'JSONP',url: '/current_details'});},// We can use the resulting promise in another// resolutionfacebookId: function($http, currentDetails) {$http({method: 'GET',url: 'http://facebook.com/api/current_user',params: {email: currentDetails.data.emails[0]}})}},controller: function($scope, person, currentDetails, facebookId) {$scope.person = person;} })
![](/assets/blank.gif)
URL
url 用来设置应用对应的一个特定状态. 也就是说,我们可以通过 url 来到达某个特定的状态,所以这里的 url 不是简单的 url 地址,而是某个可到达状态的标志。
这个特性类似于 ngRoute 中的 URL, 但是,可以被看作一个重大的升级,后面我们就会看到。
简单的路由类似下面所示。
$stateProvider.state('inbox', {url: '/inbox',template: '<h1>Welcome to your inbox</h1>'});
当我们导航到 /index 的时候,应用将会过渡到 inbox 状态,使用这里提供的内容模板填充 ui-view 的内容。
URL 中可以包含多种内容,令人难以置信的强大,可以像在 ngRoute 中设置简单的参数。
![](/assets/blank.gif)
$stateProvider.state('inbox', {url: '/inbox/:inboxId',template: '<h1>Welcome to your inbox</h1>',controller: function($scope, $stateParams) {$scope.inboxId = $stateParams.inboxId;}});
![](/assets/blank.gif)
这里,我们创建了 :inboxId 参数来捕获 url 中的第二部分,例如,如果应用访问 /inbox/1,那么,$stateParameter.inboxId 就成为 1, 实际上, $stateParams 的值将为 { inboxId: 1 }
也可以使用另外一种语法。
url: '/inbox/{inboxId}'
路径必须完全匹配,不像 ngRoute, 如果用户访问 /inbox/,这个路径配置将会工作,但是,如果访问 /inbox,这个状态就不会被激活。
还可以使用正则表达式来表示参数,这样可以通过正则表达式来设置匹配规则,例如。
![](/assets/blank.gif)
// Match only inbox ids that contain // 6 hexidecimal digits url: '/inbox/{inboxId:[0-9a-fA-F]{6}}', // Or // match every url at the end of `/inbox` // to `inboxId` (a catch-all) url: '/inbox/{inboxId:.*}'
![](/assets/blank.gif)
注意,不能在路由中使用捕获组
甚至可以在路径中使用查询参数。
// will match a route such as // /inbox?sort=ascending url: '/inbox?sort'
绝对路由
如果你使用绝对 url 方式,需要在 url 字符串的开发加上特殊字符 ^
![](/assets/blank.gif)
$stateProvider.state('contacts', {url: '/contacts',...}).state('contacts.list', {url: '^/list',...});
![](/assets/blank.gif)
'contacts'
状态将匹配"/contacts"
'contacts.list'
状态将匹配"/list"
。子状态的url没有附在父状态的url之后的,因为使用了^
。
嵌套路由
我们可以使用 url 参数添加到路由中来实现嵌套路由。这样可以提供多个 ui-views 在我们的页面中,例如,我们可以在 /inbox 之上,提供嵌套的独立路由。这里使用了子状态。
![](/assets/blank.gif)
$stateProvider.state('inbox', {url: '/inbox/:inboxId',template: '<div><h1>Welcome to your inbox</h1>\<a ui-sref="inbox.priority">Show priority</a>\<div ui-view></div>\</div>',controller: function($scope, $stateParams) {$scope.inboxId = $stateParams.inboxId;}}).state('inbox.priority', {url: '/priority',template: '<h2>Your priority inbox</h2>'});
![](/assets/blank.gif)
第一个路由与前面一样,现在还有第二个路由,一个匹配 inbox 之下的子路由,语法 (.) 表示这是一个子路由。
/inbox/1 匹配第一个状态,/inbox/1/priority 则匹配第二个状态。使用这种语法,我们可以在父路由中支持嵌套的 url。在父视图中的 ui-view 指令将会处理 priority。
Params
params 选项是参数名称或者正则的数组。它不能合并 url 选项,当状态激活的时候,应用会使用这些参数填充 $stateParams 服务。
Views
我们可以在 state 中提供命名的视图。这是强大的特性,在单个视图中,我们可以定义多个视图,甚至使用单个模板。
如果我们使用了 views 参数,那么,templateUrl, template 和 templateProvider 就会忽略。如果我们希望包含父模板,我们需要创建一个抽象模板。
假如我们有如下模板。
<div><div ui-view="filters"></div><div ui-view="mailbox"></div><div ui-view="priority"></div> </div>
主要注意的是,顶级的状态自然对应母版页中的视图,一般这个视图是 noname 的,所以,需要一个 noname 的视图来匹配这个 placeholder。其它的视图需要匹配父状态中的视图 placeholder,这些 placeholder 可以是命名的,也可以是 naname的,自然,noname 的只能有一个,否则无法进行区分,我们在 provider 中进行配置的时候,就需要描述清楚这些 view 和 placeholder 之间的对应关系。
使用 @ 可以定义绝对命名的视图名称,@ 的前面是 placeholder 的名称,后面是状态的名称。@ 前面为空表示未命名的 ui-view,@ 后面为空表示相对于根模板,通常是 index.html
我们可以创建命名的视图,然后填充对应的模板。每个子视图都可以有特有的模板,控制器和数据。
![](/assets/blank.gif)
$stateProvider.state('inbox', {views: {'filters': {template: '<h4>Filter inbox</h4>',controller: function($scope) {}},'mailbox': {templateUrl: 'partials/mailbox.html'},'priority': {template: '<h4>Priority inbox</h4>',resolve: {facebook: function() {return FB.messages();}}}}});
![](/assets/blank.gif)
在这个例子中,我们有两个命名的视图嵌套在抽象视图中。
Abstract
我们永远不能直接激活抽象模板,但是,可以通过派生模板来激活。
抽象模板提供封装命名视图的模板,可以传递 $scope 对象给派生子模板。可以通过它解决依赖问题,或者特定数据处理,或者简单地同样的 url 来嵌套多个路由,例如,所有路由都在 /admin 下面。
![](/assets/blank.gif)
$stateProvider.state('admin', {abstract: true,url: '/admin',template: '<div ui-view></div>'}).state('admin.index', {url: '/index',template: '<h3>Admin index</h3>'}).state('admin.users', {url: '/users',template: '<ul>...</ul>'});
![](/assets/blank.gif)
onEnter, onExit
在应用进入或者退出视图的时候,会调用这些回调函数。它们都可以设置回调函数;函数可以访问获取的数据。
这些回调函数可以提供我们一些能力,在访问新视图,或者改变当前状态的时候。这里是很好的执行 "Are you sure?" 对话框,或者请求用户在进入之前登陆的地方。
两个函数都不提供参数,需要的信息需要自己提供。
Data
我们可以附加任意的数到我们的状态配置对象 configObject 上,data 属性类似于 resolve 属性,除了不会注入到控制器,也不会 resolve promise。
当需要从父状态向子状态传递数据的时候,附加数据是方便的途径。
Evnets
类似 ngRoute 服务,angular-route 服务在状态生命周期的不同时间点会触发多种事件。我们可以通过在 $scope 中监听来处理这些事件。
所有的下面的事件都会在 $rootScope 中触发,所以,我们可以在任何 $scope 对象中监听这些事件。
State change events
可以如下监听
$scope.$on('$stateChangeStart', function(evt, toState, toParams, fromState, fromParams), {// We can prevent this state from completingevt.preventDefault(); });
$stateChangeStart
当从一个状态开始向另外一个状态过度的时候触发。
$stateChangeSuccess
当状态过渡完成之后触发。
$stateChangeError
在状态过渡中出现错误。常见的错误例如,不能获取模板,或者 promise 不能成功 resolve 等等
视图加载事件
ui-router 也提供了视图加载阶段的事件。
$viewContentLoading
视图开始加载,但是,在 DOM 渲染之前。
可以如下监听。
$scope.$on('$viewContentLoading', function(event, viewConfig){ // Access to all the view config properties.// and one special property 'targetView'// viewConfig.targetView });
$viewContentLoad
视图已经加载,渲染完成。
$stateParams
在前面的内容中,我们使用 $stateParams 来从 url 参数中获取 params ,这个服务,与 url 不同。
例如,如果我们 inbox 状态的 url 如下。
url: '/inbox/:inboxId/messages/{sorted}?from&to'
用户使用下面的 url 访问
/inbox/123/messages/ascending?from=10&to=20
我们的 $stateParams 对象将获取如下数据。
{inboxId: '123', sorted: 'ascending', from: 10, to: 20}
$urlRouterProvider
类似 ngRoute, 可以创建当特定的 url 访问时处理的规则。
可以通过不同的 url 激活不同的状态,所以在管理激活和加载状态的时候, $urlRouterProvider 并不是必须的。在状态管理之外的时候才会需要,比如重定向,或者验证的时候。
when()
when 函数需要两个参数,我们希望匹配的路径,另外就是我们希望重新定向的目标。也可以是一个函数。
例如,如果希望任何空的路由到我们的 /inbox 路由中。
.config(function($urlRouterProvider) {$urlRouterProvider.when('', '/inbox'); });
如果提供一个函数处理,路由匹配的时候,这个函数就会被调用,它可以返回下列三种之一的结果。
- false,这个回应告诉 $urlRouter 规则并不匹配,应该查找其它匹配的状态,在我们希望验证用户是否访问正确地址的时候很有用。
- 字符串,$urlRouter 将其作为重定向目标。
- true 或者 undefined,函数已经处理了这个 url
otherwise()
与 ngRoute 中的 oterwise() 方法类似,oterwiese() 在没有其它路由匹配的情况下重定向。这是创建默认 url 的好方法。
otherwise() 函数只需要一个参数,一个字符串或者一个函数。
如果提供了一个字符串,就会被看做一个默认地址,在任何错误的或者不能匹配任何路由的时候,就会被重定向到这个地址。
如果是一个函数,在没有其它路由匹配的时候,就会被执行
![](/assets/blank.gif)
.config(function($urlRouterProvider) {$urlRouterProvider.otherwise('/');// or$urlRouterProvider.otherwise(function($injector, $location) {$location.path('/');}); });
![](/assets/blank.gif)
rule()
如果我们希望处理任何路由,或者在其它路由之前进行一些处理,可以使用 rule() 函数。
我们必须返回一个验证的路径串
app.config(function($urlRouterProvider){$urlRouterProvider.rule(function($injector, $location) {return '/index';}); })
激活状态
有三种方式来激活特定的状态
- 使用 $state.go() 方法
- 使用 ui-sref 绑定的连接
- 直接导航到与状态关联的 url
创建报名向导
为什么不使用一下它呢?
我们创建一个报名的向导来演练一下 ui-router 的使用。
使用 ui-router ,我们创建一个简单的报名服务,使用一个控制器来处理报名。
首先,我们创建应用的视图。
<div ng-controller="WizardSignupController"><h2>Signup wizard</h2><div ui-view></div> </div>
在这个视图中,我们定义了报名视图。下一步,在报名向导中,需要三步
- start,在这一步,我们获取用户名称,提供欢迎信息
- email, 这里,我们获取用户的 email 信息
- finish, 这里,用户完成报名,我们简单地显示完成页面
报名处理依赖 wizardapp.controllers 模块,
angular.module('wizardApp', ['ui.router','wizardapp.controllers']);
我们的 wizardSignupController 控制器,使用 $scope.user 对象在整个过程中收集信息。
angular.module('wizardapp.controllers', []) .controller('WizardSignupController', ['$scope', '$state', function($scope, $state) {$scope.user = {};$scope.signup = function() {} }]);
现在,向导处理逻辑处理主要工作,配置 config()
![](/assets/blank.gif)
angular.module('wizardApp', ['ui.router', 'wizardapp.controllers']) .config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {$stateProvider.state('start', {url: '/step_1',templateUrl: 'partials/wizard/step_1.html'}).state('email', {url: '/step_2',templateUrl: 'partials/wizard/step_2.html'}).state('finish', {url: '/finish',templateUrl: 'partials/wizard/step_3.html'}); }]);
![](/assets/blank.gif)
这样,我们基本的流程就已经有了。现在,如果用户导航到 /step_1,就会看到开始页面,尽管现在地址是 /step_1, 而我们希望是 /wizard/step_1
为了这个效果,我们创建 abstract 状态来寄宿各个步骤。
![](/assets/blank.gif)
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {$stateProvider.state('wizard', {abstract: true,url: '/wizard',template: '<div><div ui-view></div></div>'}).state('wizard.start', {url: '/step_1',templateUrl: 'partials/wizard/step_1.html'}).state('wizard.email', {url: '/step_2',templateUrl: 'partials/wizard/step_2.html'}).state('wizard.finish', {url: '/finish',templateUrl: 'partials/wizard/step_3.html'}); }]);
![](/assets/blank.gif)
这样,它们都安全地嵌套到 /wizard 之下了。
在状态之间进行导航,我们使用 ui-router 提供的指令 ui-sref 来生成链接,这个指令用来生成导航链接。
例如,step_1.html 如下。
<!-- step_1.html --> <h3>Step 1</h3> <form ng-submit=""><input type="text" ng-model="user.name" placeholder="Your name" /><input type="submit" class="button" value="Next" ui-sref="wizard.email"/> </form>
我们还希望在报名流程完成之后,执行特定的动作,来调用定义在父控制器上的 signup 函数,我们可以在最后的步骤中添加一个控制器来调用 $scope.signup() 函数。由于整个向导封装在 WizardSignupControoler 中,我们可以像通常一样访问嵌套的 scope 对象。
![](/assets/blank.gif)
.state('wizard.finish', {url: '/finish',templateUrl: 'partials/wizard/step_3.html',controller: function($scope) {$scope.signup();} });
![](/assets/blank.gif)
总结
在这里,我们深入讨论了 ui-router 几乎全部的特性,我们发现这个库非常有用,希望也能帮到你。
参考资料
学习 ui-router 系列文章索引
转载于:https://www.cnblogs.com/dianli_jingjing/p/7363914.html
深入 AngularUI Router相关推荐
- AngularUI Router
UI-Router是一个让开发者能够根据URL状态或者说是'机器状态'来组织和控制界面UI的渲染,而不是仅仅的只改变路由(传统AngularJS应用实用的方式).该模块为开发者提供了很多视图(View ...
- 1、Angular-Ui Router 状态概要
状态管理器. 新的状态管理器($stateProvider) 类似于Angular's v1 的路由工作方式, 但更完美. A state corresponds to a "place&q ...
- ionic开发:第一步
为什么80%的码农都做不了架构师?>>> 1.下载安装node.js 2.输入命令行:npm install -g cordova ionic 3.输入命令行:ionic st ...
- 第二讲 html5框架+Crosswalk打包app 以及 Angularjs 基础(初步认识了解Angularjs)
第二讲 html5框架+Crosswalk打包app 以及 Angularjs 基 础(初步认识了解Angularjs) 学习要点: 1. html5框架+Crosswalk打包app 2. 什么是a ...
- 第二讲 html5 框架+Crosswalk 打包 app 以及 Angularjs 基础
第二讲 html5框架+Crosswalk 打包 app 以及 Angularjs 基础(初步认识了解 Angularjs) 学习要点: 1. html5 框架+Crosswalk 打包 a ...
- phonegap 性能优化 以及 phonegap + Angularjs + ionic 移动 app 开发介绍
第一讲 phonegap 性能优化 以及 phonegap+ Angularjs + ionic 移动 app 开发介绍 学习要点: Phonegap第一季第二季视频教程内容简介 phon ...
- AngularJS之高级Route【三】(八)
前言 我们知道默认的路由提供(Route Provider)在复杂的应用程序中是不太适合应用场景,它存在诸多限制,所以在Angular 1.2之后此时我们不得不将路由提供作为一个单独的模块当我们需要使 ...
- 收藏文章 写的很好 可惜有些还是看看不懂额。。。
http://www.infoq.com/cn/articles/backbone-vs-angular 作者 Victor Savkin ,译者 邵思华 将不同的思想和工具进行对比,是一种更好地理解 ...
- App 软件开发《填空1》试卷及答案
App 软件开发<填空1>试卷及答案 文章目录 App 软件开发<填空1>试卷及答案 填空题(共计0分) 1.[`Native App`]是指本地应用程序,又称之为原生App ...
最新文章
- 对accuracy、precision、recall、F1-score、ROC-AUC、PRC-AUC的一些理解
- 紧随Java 16,Spring Framework 5.3.5 发布:涵盖JDK 16的支持!
- C语言对内存地址的封装
- button-xml 中android:clickable=false 属性
- Sublime Text官方文档 中英文版本
- Unix/Linux环境C编程入门教程(16) LinuxMint CCPP开发环境搭建
- 使用Powershell远程管理Windows Server(WinRM)
- SAP License:把握好集成测试大关,ERP就成功了一大半
- 重新打包mysql数据库文件_服务器每天早上备份一次 MySQL 数据库并自动打包,同时删除 5 天前的备份文件...
- yolov4网络结构_上达最高精度,下到最快速度,Scaled-YOLOv4:模型缩放显神威
- 【三维路径规划】基于matlab狼群算法无人机三维路径规划【含Matlab源码 167期】
- linux下tomcat缓存磁盘文件,Linux环境下清理Tomcat缓存
- 软件外包,IT咨询和转型
- 密码编码学与网络安全
- 苹果手机和安卓手机分享的区别
- 机械臂示教轨迹参数化方法 DMP, Dynamic Movement Primitive (一)
- Android磨皮算法的实现 renderScript实现表面模糊
- cache是什么?作用是什么?位置在哪?
- 微软CEO鲍尔默失策太多次 应只拿1美元年薪
- 用Scrapy爬取分析了7万款App,结果万万没想到!
热门文章
- 《Detroit:Become Human》玩家情感故事背后的叙事魔法和体验设计
- 如何用Unity和Cardboard做一款VR游戏
- ASP.NET MVC (三、表单与文件上传)
- 【Auto.js】[系统Intent]_系统设置页面的相关intent跳转
- RabbitMQ是什么东西?
- shell调用各种sqlplus用法
- Oracle 数据字典表 -- SYS.COL$
- oracle如何导出和导入数据库/表
- Ng第二课:单变量线性回归(Linear Regression with One Variable)
- 网络路径无法访问问题的解决