ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[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'); }); }); ~~~