发表于: 2017-04-15 21:30:20
1 1128
如何使用ui-router?
路由(route),几乎所有的MVC(VM)框架都应该具有的特性,因为它是前端构建单页面应用(SPA)必不可少的组成部分。
对于angular而言,自然也有内置的路由模块-ngRoute。但由于功能的局限性,往往不能满足开发需求。于是,AngularUI团队基于ngRoute开发了第三方模块-UI-Router。ngRoute在多视图和嵌套视图上较弱,ui-router弥补了这些缺点。
2.知识剖析
UI-Router注入与配置
和ngRoute一样,UI-Router首先需要作为依赖注入应用
angular.module("myApp", ["ui.router"]).config(function($stateProvider){
$stateProvider.state(stateName, stateConfig);
})
html标签中设置视图插入位置: 如
<div ui-view=""></div>
UI-router基本参数
$stateProvider:配置应用状态
用法:$stateProvider.state(stateName,
stateConfig)
stateConfig:对象,该路由的具体配置项,url:默认相对路径(以^开头的是绝对路径)
views:每个子视图可以包含自己的模板、控制器和预载入数据。设置多视图。如果在单个状态不需要此属性。
template:
HTML字符串或者返回HTML字符串的函数(一般用templateUrl)<br>templateUrl: HTML模板的路径或者返回HTML模板路径的函数<br>controller、controllerProvider:指定任何已经被注册的控制器或者一个作为控制器的函数<br>resolve:预载入列依赖或数据,注入到控制器中。<br>onEnter,
onExit:路由进入OR退出时执行的函数
1.view:当一个页面需要嵌入多个视图时,可以配置参数,这里介绍相对路径的配置,绝对路径用@的形式,可查看官方文档
<div ui-view="filters"></div>
<div ui-view="tabledata"></div>
<div ui-view="graph"></div>
$stateProvider
.state('report',{
views: {
'filters': {
templateUrl: 'report-filters.html',//指定模板
controller: function($scope){ ... controller stuff just for filters view ... }//控制器
},
'tabledata': {
templateUrl: 'report-table.html',
controller: function($scope){ ... controller stuff just for tabledata view ... }
},
'graph': {
templateUrl: 'report-graph.html',
controller: function($scope){ ... controller stuff just for graph view ... }
}
}
})
resolve:向该路由控制器注入依赖或数据,格式{string|function}
resolve: {promiseObj: function($http){
return $http({method: 'GET', url: '/someUrl'})
.then (function (data) {
return doSomeStuffFirst(data);
});
}},
//在controller中注入promiseObj获取值
controller: function($scope,promiseObj){
$scope.items = promiseObj.data.items;
data:注入自定义数据。
3.常见问题
1、路由间参数如何传递?
2、嵌套路由父子关系如何定义?
4.解决方案
1、路由间参数如何传递?
一、通过url传递:url中传递参数也有好几种形式,如(ui-sref="a({}),$state.go('a',({}))")
url:"/contacts/:contactId" //url中传入参数为 /contacts/42
url: "/contacts/{contactId}"
//若为查询参数
url: "/contacts?myParam" //将匹配url的“/ contacts?myParam = value”
url: "/contacts?myParam1&myParam2" //will match to url of "/contacts?myParam1=value1&myParam2=wowcool"
二、通过params属性设置
.state('contacts', {
url: "/contacts",
params: {
param1: null
},
templateUrl: 'contacts.html'
})
<a ui-sref="contacts({param1: value1})">View Contacts</a> or $state.go('contacts', {param1: value1})。
2、嵌套路由父子关系如何定义?
$stateProvider
.state('contacts.list', {});//点标记法(推荐)
$stateProvider //parent属性
.state({
name: 'list', // 状态名也可以直接在配置里指定
parent: 'contacts' // 父路由的状态名
});
5.编码实战
6.扩展思考
UI-router工作原理?
路由对于前端MVC(VM)而言,就是将hash值(#xxx)与一系列的路由规则进行查找匹配,匹配出一个符合条件的规则,然后根据这个规则,进行数据的获取,以及页面的渲染。
大致过程
1.创建路由规则。
.state('home', {
url: '/abc',
template: 'hello world'
});
首先,$urlRouterProvider创建并存储一个state对象,里面包含着该路由规则的所有配置信息。然后,调用$urlRouterProvider.when(...)方法,进行路由的注册(之前是路由的创建)。
2.路由查找匹配
(1)angular 在刚开始的$digest时,$rootScope会触发$locationChangeSuccess事件(angular在每次浏览器hash change的时候也会触发$locationChangeSuccess事件)(2)ui.router
监听了$locationChangeSuccess事件,于是开始通过遍历一系列rules,进行路由查找匹配
(3)当匹配到路由后,就通过$state.transitionTo(state,...),跳转激活对应的state
(4)最后,完成数据请求和模板的渲染
当我们访问http://xxxx#/abc的时候,这个路由规则被匹配到,对应的模板会被填到某个div[ui-view]中。
一般路由要对rules进行遍历,但ui-router进行了优化:
ui.router在创建路由时,会实例化一个对应的state对象,并存储起来(states集合里面),每一个state对象都有一个state.name进行唯一标识(如:'home')
当通过ui-sref(会调用$state.go())指令或直接通过$state.go()跳转时,ui-sref="home"指令会给对应的dom添加click事件,然后根据state.name,直接跳转到对应的state,跳转到对应的state之后,ui.router会改变hash,所以触发’$locationChangeSuccess'事件,然后执行回调,在回调中通过一个判断代码规避循环rules。
所以尽量避免直接使用href="#/xxx"来改变hash,然后跳转到对应state。这么做将进行rules遍历,浪费性能。
7.参考文献
参考一:<a href="http://www.cnblogs.com/01-02/p/6071392.html" target="_blank">angular中的路由</a>
参考二:<a href="https://github.com/angular-ui/ui-router/wiki/Quick-Reference#stateprovider-1"
target="_blank">uiroueter官方文档</a></p>
参考三:<a href="https://www.oschina.net/translate/angularjs-ui-router-nested-routes" target="_blank">AngularJS
ui-router (嵌套路由)</a>
8.更多讨论
uiRouter中还要很多对应事件,了解之后在项目中很有帮助
state事件
$rootScope.$on('$stateChangeStart', function(event,toState, toParams, fromState, fromParams){ ... })
$rootScope.$on('$stateNotFound', function(event, unfoundState, fromState, fromParams){ ... })
$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){ .. })
$rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams,error){ ... })
view事件:View被加载但是DOM树构建之前时:
$scope.$on('$viewContentLoading', function(event, viewConfig){ ... });
View被加载而且DOM树构建完成时:$scope.$on('$viewContentLoaded', function(event){ ... });
评论