[TOC]
# 路由状态管理
## ui-router以状态为核心
ui-router 的工作原理非常类似于 Angular 的路由控制器,但它只关注状态。
* 在应用程序的整个用户界面和导航中,一个状态对应于一个页面位置
* 通过定义controller、template和view等属性,来定义指定位置的用户界面和界面行为
* 通过嵌套的方式来解决页面中的一些重复出现的部位
## 加载路由模块
### 路由js文件加载
~~~
bower install angular-ui-router --save
~~~
### 项目模块加载依赖
~~~
angular.module('myapp', ['ui.router']);
~~~
## 项目模块中配置项目路由
### 使用Angular模块对象的config方法配置
一般会在Angular的config方法中配置路由,config方法需要依赖两个对象$stateProvider, $urlRouterProvider
~~~
angular.module('myapp').config(function ($stateProvider, $urlRouterProvider) {
});
~~~
## 路由状态管理
### $stateProvider对象的state方法基本用法
理由状态管理使用的是$stateProvider对象的state方法
~~~
//参数1:String 路由名称
//参数2:Object 路由状态对象配置
$stateProvider.state('contacts',{});
~~~
## 路由状态模板属性Templates 模板
### 方法一:配置template属性,指定一段 HTML 字符串,这人是设置模板的最简单的方式
【js文件】
~~~
angular.module('myapp', ['ui.router']);
angular.module('myapp').config(function ($stateProvider, $urlRouterProvider) {
//home是路由名称,在HTML页面中可以使用ui-sref绑定
$stateProvider.state('home',{
template:'<h1>这里是HZJ</h1>'
});
});
~~~
【html文件】
~~~
<div ng-controller="indexCtl">
<!--使用ui-sref指令绑定路由名称-->
<button ui-sref="home">点击</button>
<hr>
<!--使用ui-view【A】指令显示路由模板内容,并且自动产生作用域-->
<div ui-view></div>
<hr>
<!--ui-view指令也可以使用【E】并且自动产生作用域-->
<ui-view></ui-view>
</div>
~~~
### 方法二:配置templateUrl属性,来加载指定位置的模板,这是设置模板的常用方法。
templateUrl的值也可以是一个函数返回的url,函数带一个预设参数stateParams。
【js文件templateUrl字符串】
~~~
angular.module('myapp', ['ui.router']);
angular.module('myapp').config(function ($stateProvider, $urlRouterProvider) {
//home是路由名称,在HTML页面中可以使用ui-sref绑定
$stateProvider.state('home',{
templateUrl:'homeTpl.html'
});
});
~~~
【js文件使用templateUrl函数】
~~~
angular.module('myapp', ['ui.router']);
angular.module('myapp').config(function ($stateProvider, $urlRouterProvider) {
//home是路由名称,在HTML页面中可以使用ui-sref绑定
$stateProvider.state('home',{
//templateUrl可以是一个函数,然后由函数返回一个字符串
templateUrl:function (stateParams) {
return 'homeTpl.html';
}
});
});
~~~
### 方法三:通过templateProvider函数返回模板的 HTML。
如果想在状态被激活前,让<ui-view>有一些默认的内容,当状态被激活之后默认内容将被状态对应的模板替换。
【js文件,使用templateProvider函数】
~~~
angular.module('myapp', ['ui.router']);
angular.module('myapp').config(function ($stateProvider, $urlRouterProvider) {
//home是路由名称,在HTML页面中可以使用ui-sref绑定
$stateProvider.state('home',{
//使用templateProvider返回一个模板
templateProvider: function ($timeout) {
return $timeout(function () {
return '<h1>dddddddddd</h1>'
}, 100);
}
});
});
~~~
【html文件,在路由结果还没有在ui-view渲染时,默认写点html】
~~~
<div ng-controller="indexCtl">
<!--使用ui-sref指令绑定路由名称-->
<button ui-sref="home">点击</button>
<hr>
<!--使用ui-view【A】指令显示路由模板内容,并且自动产生作用域-->
<div ui-view>
<h1>这里是路由结果还没有加载的默认结果嘿嘿</h1>
</div>
</div>
~~~
## 路由状态激活和渲染
【项目结构】
![](https://box.kancloud.cn/a15a0e6b40c083222fb739f699cc9e0a_772x628.png)
【app.js文件】
~~~
angular.module('myapp', ['ui.router']);
angular.module('myapp').config(function ($stateProvider, $urlRouterProvider) {
//home是路由名称,在HTML页面中可以使用ui-sref绑定
$stateProvider.state('home',{
templateUrl:'homeTpl.html'
});
});
~~~
【homeTpl.html文件】
~~~
<h1>这里是home</h1>
~~~
【index.html文件】
~~~
<!DOCTYPE html>
<html lang="en" ng-app="myapp">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="css/mystyle.css">
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/angular-ui-router/release/angular-ui-router.js"></script>
<script src="app.js"></script>
<script src="indexCtl.js"></script>
</head>
<body>
<div ng-controller="indexCtl">
<!--使用ui-sref指令绑定路由名称-->
<button ui-sref="home">点击</button>
<!--任何标签都可以使用ui-sref指令-->
<a ui-sref="home">HOME页面</a>
<button ng-click="gotoHome()">使用$state.go方法</button>
<hr>
<!--使用ui-view【A】指令显示路由模板内容,并且自动产生作用域-->
<div ui-view>
<h1>这里是路由结果还没有加载的默认结果嘿嘿</h1>
</div>
</div>
</body>
</html>
~~~
【indexCtl.js】
~~~
//控制器indexCtl
angular.module('myapp').controller('indexCtl',['$state','$scope',function ($state,$scope) {
//使用$state.go方法
$scope.gotoHome=function () {
//参数为路由状态名称
$state.go('home');
};
}]);
~~~
### 使用ui-sref指令激活路由
【HTML中任意组件都能使用ui-sref指令,但是ui-sref指令只支持点击事件】
~~~
<!--使用ui-sref指令绑定路由名称-->
<button ui-sref="home">点击</button>
<!--任何标签都可以使用ui-sref指令-->
<a ui-sref="home">HOME页面</a>
~~~
### 使用$state.go方法
【HTML界面】
~~~
<button ng-click="gotoHome()">使用$state.go方法</button>
~~~
【控制器先依赖$tate对象,然后在使用go方法,方法参数为路由状态名称】
~~~
//控制器indexCtl
angular.module('myapp').controller('indexCtl',['$state','$scope',function ($state,$scope) {
//使用$state.go方法
$scope.gotoHome=function () {
//参数为路由状态名称
$state.go('home');
};
}]);
~~~
### 使用ui-view指令渲染路由结果
【HTML中使用ui-view指令即可,该指令可以是E也可以是A,指令内容会被路由状态模板替换】
~~~
<div ui-view>
<h1>这里是路由结果还没有加载的默认结果嘿嘿</h1>
</div>
~~~
## 路由状态模板控制器属性Controller
### 可以为模板指定一个控制器(controller)。警告:如果模板没有定义,那么控制器不会被实例化。
【路由状态模板文件homeTpl.html】
~~~
<h1>这里是home</h1>
<p>{{data}}</p>
~~~
【控制器文件app.js】
~~~
angular.module('myapp', ['ui.router']);
angular.module('myapp').config(function ($stateProvider, $urlRouterProvider) {
//home是路由名称,在HTML页面中可以使用ui-sref绑定
$stateProvider.state('home',{
templateUrl:'homeTpl.html',
//$scope参数绑定作用域数据
controller:function ($scope) {
$scope.data='hzj';
}
});
});
~~~
### 如果在模块中已经定义了一个控制器,只需要指定控制器的名称即可
【路由状态模板文件homeTpl.html】
~~~
<h1>这里是home</h1>
<p>{{data}}</p>
~~~
【控制器文件app.js】
~~~
angular.module('myapp', ['ui.router']);
angular.module('myapp').config(function ($stateProvider, $urlRouterProvider) {
//home是路由名称,在HTML页面中可以使用ui-sref绑定
$stateProvider.state('home',{
templateUrl:'homeTpl.html',
//$scope参数绑定作用域数据
controller:'Ctrl1'
});
});
//控制器单独写
angular.module('myapp').controller('Ctrl1',['$scope',function ($scope) {
$scope.data='hzj';
}]);
~~~
## 路由状态解决器Resolve属性
### 路由状态解决器Resolve可以选择性的为控制器注入依赖对象
* resolve配置项是一个由key/value构成的对象。
* key – {string}:注入控制器的依赖项名称。
* value - {string|function}:
* string:一个服务的别名
* function:函数的返回值将作为依赖注入项,如果函数是一个耗时的操作,那么控制器必须等待该函数执行完成(be resolved)才会被实例化。
【app.js】
~~~
angular.module('myapp', ['ui.router']);
//创建一个factory服务
angular.module('myapp').factory('factoryHzj',function () {
return 'factory服务';
});
angular.module('myapp').config(function ($stateProvider, $urlRouterProvider) {
//home是路由名称,在HTML页面中可以使用ui-sref绑定
$stateProvider.state('home', {
templateUrl: 'homeTpl.html',
//$scope参数绑定作用域数据
controller: 'Ctrl1',
//resolve本身是一个对象,每个对象的key要么是对象、要么是字符串,如果是字符串那么为注入服务
resolve: {
//data属性利用函数返回了一个对象,该对象有一个属性为value,值为hzj
data: function () {
//结果对象
var result = {value: 'hzj1111'};
//返回结果对象
return result;
},
//data1属性利用函数返回一个函数,因为函数也是对象
data1: function () {
var fun=function (a,b) {
return a+b;
};
return fun;
},
//data2属性利用函数返回一个数组,因为数组也是对象
data2:function () {
var array=[1,2,3,4,5,6];
return array;
},
//data3属性利用函数的可以任意的使用Angular的服务,这里使用了$location服务
data3:function ($location) {
return $location.absUrl();
},
//直接字符串,代表直接使用服务名称
data4:'factoryHzj'
},
});
});
//控制器单独写
//依赖resolve中的所有data,data1,data2,data3
angular.module('myapp').controller('Ctrl1', function ($scope,data,data1,data2,data3,data4) {
$scope.a = 'hzj';
$scope.b = data.value;
$scope.c = data1(1,2);
$scope.d = data2;
$scope.e = data3;
$scope.f = data4;
});
~~~
【homeTpl.html】
~~~
<h1>这里是home</h1>
<p>{{a}}</p>
<p>{{b}}</p>
<p>{{c}}</p>
<p>{{d}}</p>
<p>{{e}}</p>
<p>{{f}}</p>
~~~
## 路由状态自定义数据对象data属性
### 为 $state 对象提供自定义数据
可以给 $state 对象提供自定义数据(建议使用data属性,以免冲突,因为可以使用任意属性名称)
【app.js】
~~~
angular.module('myapp', ['ui.router']);
angular.module('myapp').config(function ($stateProvider, $urlRouterProvider) {
//home是路由名称,在HTML页面中可以使用ui-sref绑定
$stateProvider.state('home', {
templateUrl: 'homeTpl.html',
//$scope参数绑定作用域数据
controller: 'Ctrl1',
//添加自定义数据,这里是建议使用data名称,避免与原始属性冲突
//这里添加了data、data1、data2、data3等三个自定义路由状态数据
data:'hzj111',
data1:{name:'hzj'},
data2:[1,2,3,4,5,5,6],
data3:function (a,b) {
return a+b;
},
});
});
//控制器单独写
//注入$state对象
//然后调用$state对象的current属性获取当前路由状态对象
angular.module('myapp').controller('Ctrl1', function ($scope,$state) {
$scope.a = 'hzj';
$scope.b = $state.current.data;
$scope.c = $state.current.data1.name;
$scope.d = $state.current.data2[2];
$scope.e = $state.current.data3(100,200);
});
~~~
【homeTpl.html】
~~~
<h1>这里是home</h1>
<p>{{a}}</p>
<p>{{b}}</p>
<p>{{c}}</p>
<p>{{d}}</p>
<p>{{e}}</p>
~~~
## 路由状态自定义数据对象onEnter 和 onExit 属性
### onEnter和onExit属性分别称为当一个状态变得活跃的和不活跃的时候触发。回调函数也可以访问所有解决依赖项。
【app.js】
~~~
angular.module('myapp', ['ui.router']);
angular.module('myapp').config(function ($stateProvider, $urlRouterProvider) {
//home是路由名称,在HTML页面中可以使用ui-sref绑定
$stateProvider.state('home', {
templateUrl: 'homeTpl.html',
//$scope参数绑定作用域数据
controller: 'Ctrl1',
//当路由状态激活触发
onEnter:function () {
console.log('进入');
},
//当路由状态离开触发
onExit:function () {
console.log('离开');
}
});
});
//控制器单独写
angular.module('myapp').controller('Ctrl1', function ($scope) {
});
~~~
## State Change Events 状态改变事件
### 路由状态改变时触发一系列事件【该事件只会在$rootScope作用域触发】
* $stateChangeStart - 当模板开始解析之前触发【注意:使用event.preventDefault()可以阻止模板解析的发生】
* $stateNotFound - v0.3.0 - 在 transition 时通过状态名查找状态,当状态无法找到时发生。该事件在 scope 链上广播,只允许一次处理错误的机会。unfoundState将作为参数传入事件监听函数,下面例子中可以看到unfoundState的三个属性。使用 event.preventDefault() 来阻止模板解析,
* $stateChangeSuccess - 当模板解析完成后触发
* $stateChangeError - 当模板解析过程中发生错误时触发
【app.js】
~~~
//在模块的run方法中使用$rootScope是一个比较合适的选择
angular.module('myapp').run(function ($rootScope) {
//当模板开始解析之前触发
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
//注意:使用event.preventDefault()可以阻止模板解析的发生
// event.preventDefault();
console.log('$stateChangeStart');
});
// $stateNotFound在transition 时通过状态名查找状态,当状态无法找到时发生。
// 该事件在 scope 链上广播,只允许一次处理错误的机会。
$rootScope.$on('$stateNotFound', function (event, unfoundState, fromState, fromParams) {
console.log('$stateNotFound');
});
// $stateChangeSuccess - 当模板解析完成后触发
$rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) {
console.log('$stateChangeSuccess');
});
// $stateChangeError - 当模板解析过程中发生错误时触发
$rootScope.$on('$stateChangeError', function (event, toState, toParams, fromState, fromParams, error) {
console.log('$stateChangeError');
});
});
~~~
## View Load Events 视图加载事件
### 视图加载的时候触发一系列事件
$viewContentLoading - 当视图开始加载,DOM渲染完成之前触发,该事件将在$scope链上广播此事件。
$viewContentLoaded - 当视图加载完成,DOM渲染完成之后触发,视图所在的$scope发出该事件。
【app.js】
~~~
angular.module('myapp').config(function ($stateProvider, $urlRouterProvider) {
//home是路由名称,在HTML页面中可以使用ui-sref绑定
$stateProvider.state('home', {
templateUrl: 'homeTpl.html',
//$scope参数绑定作用域数据
controller: 'Ctrl1',
//当路由状态激活触发
onEnter: function () {
console.log('进入');
},
//当路由状态离开触发
onExit: function () {
console.log('离开');
}
});
});
//控制器单独写
angular.module('myapp').controller('Ctrl1', function ($scope) {
//$viewContentLoading - 当视图开始加载,DOM渲染完成之前触发,该事件将在$scope链上广播此事件。
$scope.$on('$viewContentLoading', function (event, viewName) {
console.log('$viewContentLoading..................');
});
//$viewContentLoaded - 当视图加载完成,DOM渲染完成之后触发,视图所在的$scope发出该事件。
$scope.$on('$viewContentLoaded', function (event, viewName) {
console.log('$viewContentLoaded');
});
});
~~~
- Angular简介
- angular1资料网站
- Angular初级部分
- 打破传统的前端
- Angular基本组成部分
- Angular环境搭建
- Angular项目测试
- Angular基础概念
- Angular模块
- Angular控制器
- Angular指令
- Angular表达式
- Angular视图
- Angular基础实战
- Angular模块创建和使用
- Angular控制器和模型创建
- scope对象
- 控制器中调度window对象和document对象
- Angular表达式调度过滤器
- Angular中的ng模块全局方法
- Angular模板应用
- 使用指令复制元素
- 使用指令隐藏显示元素
- Angular指令ng-if
- ng-src和ng-href
- Angular处理样式
- Angular作用域事件传递
- 表单中的元素
- Angular初学者常见的坑
- 再论双向绑定
- Angular中级部分
- Angular路由机制
- ui-router管理状态
- ui-router状态嵌套和视图嵌套
- ui-router多个命名的视图
- ui-router路由控制
- 自定义指令
- 自定义过滤器
- Angular项目目录结构
- Angular服务
- Angular高级部分
- Angular依赖注入
- README