翻译:深入 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。

.config(function($stateProvider, $urlRouterProvider) {$stateProvider.state('start', {url: '/start',templateUrl: 'partials/start.html'})
});

这样,我们;定义了名为 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 中。

$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;}
})

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 中设置简单的参数。

$stateProvider.state('inbox', {url: '/inbox/:inboxId',template: '<h1>Welcome to your inbox</h1>',controller: function($scope, $stateParams) {$scope.inboxId = $stateParams.inboxId;}});

这里,我们创建了 :inboxId 参数来捕获 url 中的第二部分,例如,如果应用访问 /inbox/1,那么,$stateParameter.inboxId 就成为 1, 实际上, $stateParams 的值将为 { inboxId: 1 }

也可以使用另外一种语法。

url: '/inbox/{inboxId}'

路径必须完全匹配,不像 ngRoute, 如果用户访问 /inbox/,这个路径配置将会工作,但是,如果访问 /inbox,这个状态就不会被激活。

还可以使用正则表达式来表示参数,这样可以通过正则表达式来设置匹配规则,例如。

// 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:.*}'

注意,不能在路由中使用捕获组

甚至可以在路径中使用查询参数。

// will match a route such as
// /inbox?sort=ascending
url: '/inbox?sort'

绝对路由

如果你使用绝对 url 方式,需要在 url 字符串的开发加上特殊字符 ^

$stateProvider.state('contacts', {url: '/contacts',...}).state('contacts.list', {url: '^/list',...});

  • 'contacts'状态将匹配"/contacts"
  • 'contacts.list'状态将匹配"/list"。子状态的url没有附在父状态的url之后的,因为使用了^

嵌套路由

我们可以使用 url 参数添加到路由中来实现嵌套路由。这样可以提供多个 ui-views 在我们的页面中,例如,我们可以在 /inbox 之上,提供嵌套的独立路由。这里使用了子状态。

$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>'});

第一个路由与前面一样,现在还有第二个路由,一个匹配 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

我们可以创建命名的视图,然后填充对应的模板。每个子视图都可以有特有的模板,控制器和数据。

$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();}}}}});

在这个例子中,我们有两个命名的视图嵌套在抽象视图中。

Abstract

我们永远不能直接激活抽象模板,但是,可以通过派生模板来激活。

抽象模板提供封装命名视图的模板,可以传递 $scope 对象给派生子模板。可以通过它解决依赖问题,或者特定数据处理,或者简单地同样的 url 来嵌套多个路由,例如,所有路由都在 /admin 下面。

$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>'});

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() 函数只需要一个参数,一个字符串或者一个函数。

如果提供了一个字符串,就会被看做一个默认地址,在任何错误的或者不能匹配任何路由的时候,就会被重定向到这个地址。

如果是一个函数,在没有其它路由匹配的时候,就会被执行

.config(function($urlRouterProvider) {$urlRouterProvider.otherwise('/');// or$urlRouterProvider.otherwise(function($injector, $location) {$location.path('/');});
});

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()

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'});
}]);

这样,我们基本的流程就已经有了。现在,如果用户导航到 /step_1,就会看到开始页面,尽管现在地址是 /step_1, 而我们希望是 /wizard/step_1

为了这个效果,我们创建 abstract 状态来寄宿各个步骤。

.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'});
}]);

这样,它们都安全地嵌套到 /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 对象。

.state('wizard.finish', {url: '/finish',templateUrl: 'partials/wizard/step_3.html',controller: function($scope) {$scope.signup();}
});

总结

在这里,我们深入讨论了 ui-router 几乎全部的特性,我们发现这个库非常有用,希望也能帮到你。

参考资料

学习 ui-router 系列文章索引

分类: Web Front,AngularJS

转载于:https://www.cnblogs.com/dianli_jingjing/p/7363914.html

深入 AngularUI Router相关推荐

  1. AngularUI Router

    UI-Router是一个让开发者能够根据URL状态或者说是'机器状态'来组织和控制界面UI的渲染,而不是仅仅的只改变路由(传统AngularJS应用实用的方式).该模块为开发者提供了很多视图(View ...

  2. 1、Angular-Ui Router 状态概要

    状态管理器. 新的状态管理器($stateProvider) 类似于Angular's v1 的路由工作方式, 但更完美. A state corresponds to a "place&q ...

  3. ionic开发:第一步

    为什么80%的码农都做不了架构师?>>>    1.下载安装node.js 2.输入命令行:npm install -g cordova ionic 3.输入命令行:ionic st ...

  4. 第二讲 html5框架+Crosswalk打包app 以及 Angularjs 基础(初步认识了解Angularjs)

    第二讲 html5框架+Crosswalk打包app 以及 Angularjs 基 础(初步认识了解Angularjs) 学习要点: 1. html5框架+Crosswalk打包app 2. 什么是a ...

  5. 第二讲 html5 框架+Crosswalk 打包 app 以及 Angularjs 基础

     第二讲 html5框架+Crosswalk 打包 app 以及 Angularjs 基础(初步认识了解 Angularjs)   学习要点: 1. html5 框架+Crosswalk 打包 a ...

  6. phonegap 性能优化 以及 phonegap + Angularjs + ionic 移动 app 开发介绍

     第一讲  phonegap 性能优化 以及 phonegap+ Angularjs + ionic 移动 app 开发介绍   学习要点: Phonegap第一季第二季视频教程内容简介 phon ...

  7. AngularJS之高级Route【三】(八)

    前言 我们知道默认的路由提供(Route Provider)在复杂的应用程序中是不太适合应用场景,它存在诸多限制,所以在Angular 1.2之后此时我们不得不将路由提供作为一个单独的模块当我们需要使 ...

  8. 收藏文章 写的很好 可惜有些还是看看不懂额。。。

    http://www.infoq.com/cn/articles/backbone-vs-angular 作者 Victor Savkin ,译者 邵思华 将不同的思想和工具进行对比,是一种更好地理解 ...

  9. App 软件开发《填空1》试卷及答案

    App 软件开发<填空1>试卷及答案 文章目录 App 软件开发<填空1>试卷及答案 填空题(共计0分) 1.[`Native App`]是指本地应用程序,又称之为原生App ...

最新文章

  1. 对accuracy、precision、recall、F1-score、ROC-AUC、PRC-AUC的一些理解
  2. 紧随Java 16,Spring Framework 5.3.5 发布:涵盖JDK 16的支持!
  3. C语言对内存地址的封装
  4. button-xml 中android:clickable=false 属性
  5. Sublime Text官方文档 中英文版本
  6. Unix/Linux环境C编程入门教程(16) LinuxMint CCPP开发环境搭建
  7. 使用Powershell远程管理Windows Server(WinRM)
  8. SAP License:把握好集成测试大关,ERP就成功了一大半
  9. 重新打包mysql数据库文件_服务器每天早上备份一次 MySQL 数据库并自动打包,同时删除 5 天前的备份文件...
  10. yolov4网络结构_上达最高精度,下到最快速度,Scaled-YOLOv4:模型缩放显神威
  11. 【三维路径规划】基于matlab狼群算法无人机三维路径规划【含Matlab源码 167期】
  12. linux下tomcat缓存磁盘文件,Linux环境下清理Tomcat缓存
  13. 软件外包,IT咨询和转型
  14. 密码编码学与网络安全
  15. 苹果手机和安卓手机分享的区别
  16. 机械臂示教轨迹参数化方法 DMP, Dynamic Movement Primitive (一)
  17. Android磨皮算法的实现 renderScript实现表面模糊
  18. cache是什么?作用是什么?位置在哪?
  19. 微软CEO鲍尔默失策太多次 应只拿1美元年薪
  20. 用Scrapy爬取分析了7万款App,结果万万没想到!

热门文章

  1. 《Detroit:Become Human》玩家情感故事背后的叙事魔法和体验设计
  2. 如何用Unity和Cardboard做一款VR游戏
  3. ASP.NET MVC (三、表单与文件上传)
  4. 【Auto.js】[系统Intent]_系统设置页面的相关intent跳转
  5. RabbitMQ是什么东西?
  6. shell调用各种sqlplus用法
  7. Oracle 数据字典表 -- SYS.COL$
  8. oracle如何导出和导入数据库/表
  9. Ng第二课:单变量线性回归(Linear Regression with One Variable)
  10. 网络路径无法访问问题的解决