Angularjs中UI Router全攻略

首先给大家介绍angular-ui-router的基本用法

如何引用依赖angular-ui-router

rush:js;"> angular.module('app',["ui.router"]) .config(function($stateProvider){ $stateProvider.state(stateName,stateCofig); })

$stateProvider.state(stateName,stateConfig)

stateName是string类型 stateConfig是object类型 //statConfig可以为空对象 $stateProvider.state("home",{}); //state可以有子父级 $stateProvider.state("home",{}); $stateProvider.state("home.child",{}) //state可以是链式的 $stateProvider.state("home",{}).state("about",{}).state("photos",{});

stateConfig包含的字段:template,templateUrl,templateProvider,controller,controllerProvider,resolve,url,params,views,abstract,onEnter,onExit,reloadOnSearch,data

$urlRouteProvider

$urlRouteProvider.when(whenPath,toPath) $urlRouterProvider.otherwise(path) $urlRouteProvider.rule(handler)

$state.go

$state.go(to,[,toParams],options]) 形参to是string类型,必须,使用"^"或"."表示相对路径; 形参toParams可空,类型是对象; 形参options可空,类型是对象,字段包括:location为bool类型认true,inherit为bool类型认true,relative为对象认$state.$current,notify为bool类型认为true,reload为bool类型认为false

$state.go('photos.detail') $state.go('^')到上一级,比如从photo.detail到photo $state.go('^.list')到相邻state,比如从photo.detail到photo.list $state.go('^.detail.comment')到孙子级state,比如从photo.detail到photo.detial.comment

ui-sref

ui-sref='stateName' ui-sref='stateName({param:value,param:value})'

ui-view

==没有名称的ui-view

rush:js;">
$stateProvider.state("home",{ template: "

hi

" })

或者这样配置:

rush:js;"> $stateProvider.state("home"{ views: { "": { template: "

hi

" } } })

==有名称的ui-view

rush:js;">
$stateProvider.state("home",{ views: { "main" : { template: "

hi

" } } })

==多个ui-view

rush:js;">
$stateProvider.state("home",{ views: { "":{template: "

hi

"},"data": {template: "
data
"} } })

项目文件结构

node_modules/ partials/ .....about.html .....home.html .....photos.html app.js index.html

创建state和view

app.js

rush:js;"> var photogallery = angular.module('photogallery',["ui.router"]); photogallery.config(function($stateProvider,$urlRouterProvider){ $urlRouterProvider.otherwise('/home'); $stateProvider .state('home',{ url: '/home',templateUrl: 'partials/home.html' }) .state('photos',{ url: '/photos',templateUrl: 'partials/photos.html' }) .state('about',{ url: '/about',templateUrl: 'partials/about.html' }) })

index.html

rush:js;"> gallery"> <Meta charset="UTF-8"> dist/css/bootstrap.css"/>

Welcome

state之间的跳转

index.html

rush:js;">

以上通过ui-sref属性完成state之间的跳转。

多个view以及state嵌套

有时候,一个页面上可能有多个ui-view,比如:

假设,以上页面属于一个名称为parent的state中。

我们知道在ui-router中,一个state大致是这样设置的:

所有state下views下的所有键值对(类似 "body@content":{templateUrl: 'partials/photos.html'})都被放到一个键值集合中。而ui-view的工作原理就是根据自己的属性值,到这个键值集合中去找匹配的键,找到就把对应的页面显示出来。

点击header对应的页面链接,可能会跳转到另外的子页面出现在

index.html 这时变成了这样

app.js 路由现在这样设置

rush:js;"> var photogallery = angular.module('photogallery',$urlRouterProvider){ $urlRouterProvider.otherwise('home'); $stateProvider .state('content',{ url: '/',views:{ "":{templateUrl: 'partials/content.html'},"header@content":{templateUrl: 'partials/header.html'},} }) .state('content.home',{ url: 'home',views:{ "body@content":{templateUrl: 'partials/home.html'} } }) .state('content.photos',{ url: 'photos',views:{ "body@content":{templateUrl: 'partials/photos.html'} } }) .state('content.about',{ url:'about',views:{ "body@content":{templateUrl: 'partials/about.html'} } }) })

这时候,页面是这样呈现出来的:

→ 来到home这个路由

rush:js;"> .state('content.home',views:{ "body@content":{templateUrl: 'partials/home.html'} } })

以上,告诉我们partials/home.html将会被加载到与"body@content"匹配的ui-view中。暂时对应的ui-view还没有出现,于是等待。

→ 路由看到index.html上的

rush:js;"> .state('content',} })

于是,就找到了content这个state下views下的 "":{templateUrl: 'partials/content.html'}这个键值对,把partials/content.html显示出来。

→ 分别加载partials/content.html页面上的各个部分

看到

,就加载如下:

"header@content":{templateUrl: 'partials/header.html'},

看到

,先加载 "body@content":{templateUrl: 'partials/home.html'}

→ 点击header上的链接

点击,来到:

把partials/photos.html显示到

中去。

点击

,来到:

把partials/about.html显示到

中去。

state多级嵌套

以上,在路由设置中,state名称有content,content.photos有了这样的一层嵌套。接下来,要实现state的多级嵌套。

在photos.html页面准备加载一个子页面,叫做photos-list.html; 与photo-list.html页面相邻的还有一个页面,叫做photo-detail.html; 在photo-detail.html页面上加载一个子页面,叫做photos-detail-comment.html;

这样,页面有了嵌套关系,state也相应的会有嵌套关系。

现在,文件结构变成:

node_modules/ partials/ .....about.html .....home.html .....photos.html .....content.html .....header.html .....photos-list.html .....photo-detail.html .....photos-detail-comment.html app.js index.html

photos.html 加一个容纳子页面的ui-view

photos

如何到达这个子页面呢?修改header中的相关部分如下:

以上,通过来到photos.html的子页面photos-list.html.

photos-list.html 通过2种途径到相邻页photo-detail.html

photo-detail.html 又提供了来到其子页面photos-detail-comment.html的ui-view

photos-detail-comment.html 则很简单:

photos-detail-comment

app.js state多级嵌套的设置为

rush:js;"> var photogallery = angular.module('photogallery',views:{ "body@content":{templateUrl: 'partials/photos.html'} } }) .state('content.photos.list',{ url: '/list',templateUrl: 'partials/photos-list.html' }) .state('content.photos.detail',{ url: '/detail',templateUrl: 'partials/photos-detail.html' }) .state('content.photos.detail.comment',{ url: '/comment',templateUrl: 'partials/photos-detail-comment.html' }) .state('content.about',views:{ "body@content":{templateUrl: 'partials/about.html'} } }) })

抽象state

如果一个state,没有通过链接找到它,那就可以把这个state设置为abstract:true,我们把以上的content和content.photos这2个state设置为抽象。

rush:js;"> .state('content',abstract: true,} }) ... .state('content.photos',views:{ "body@content":{templateUrl: 'partials/photos.html'} } })

那么,当一个state设置为抽象,如果通过ui-sref或路由导航到该state会出现什么结果呢?

--会导航到认路由上

$urlRouterProvider.otherwise('home');

rush:js;"> .state('content.home',views:{ "body@content":{templateUrl: 'partials/home.html'} } })

最终把partials/home.html显示出来。

使用控制器

在实际项目中,数据大多从controller中来。

首先在路由中设置state所用到的控制器以及控制器别名。

rush:js;"> var photogallery = angular.module('photogallery',views:{ "body@content":{ templateUrl: 'partials/home.html',controller: 'HomeController',controllerAs: 'ctrHome' } } }) .state('content.photos',views:{ "body@content":{ templateUrl: 'partials/photos.html',controller: 'PhotoController',controllerAs: 'ctrPhoto' } } }) .state('content.photos.list',templateUrl: 'partials/photos-list.html',controller: "PhotoListController",controllerAs: 'ctrPhotoList' }) .state('content.photos.detail',templateUrl: 'partials/photos-detail.html',controller: 'PhotoDetailController',controllerAs: 'ctrPhotoDetail' }) .state('content.photos.detail.comment',views:{ "body@content":{templateUrl: 'partials/about.html'} } }) })

添加controller.js,该文件用来定义所用到的controller.现在的文件结构为:

asserts/ .....css/ .....images/ ..........image1.jpg ..........image2.jpg ..........image3.jpg ..........image4.jpg node_modules/ partials/ .....about.html .....home.html .....photos.html .....content.html .....header.html .....photos-list.html .....photo-detail.html .....photos-detail-comment.html app.js

index.html

controllers.js

rush:js;"> photogallery.controller('HomeController',['$scope','$state',function($scope,$state){ this.message = 'Welcome to the Photo gallery'; }]); //别名:ctrPhoto photogallery.controller('PhotoController',$state){ this.photos = [ { id: 0,title: 'Photo 1',description: 'description for photo 1',imageName: 'image1.jpg',comments:[ {name: 'user1',comment: 'Nice'},{ name:'User2',comment:'Very good'} ]},{ id: 1,title: 'Photo 2',description: 'description for photo 2',imageName: 'image2.jpg',comments:[ { name: 'user2',{ name:'User1',{ id: 2,title: 'Photo 3',description: 'description for photo 3',imageName: 'image3.jpg',comment: 'Nice'} ]},{ id: 3,title: 'Photo 4',description: 'description for photo 4',imageName: 'image4.jpg',comment:'Very good'},{ name:'User3',comment:'So so'} ]} ]; //给子state下controller中的photos赋值 this.pullData = function(){ $scope.$$childTail.ctrPhotoList.photos = this.photos; } }]); //别名:ctrPhotoList photogallery.controller('PhotoListController',$state){ this.reading = false; this.photos = new Array(); this.init = function(){ this.reading = true; setTimeout(function(){ $scope.$apply(function(){ $scope.ctrPhotoList.getData(); }); },1500); } this.getData = function(){ //调用父state中controller中的方法 $scope.$parent.ctrPhoto.pullData(); /*this.photos = $scope.$parent.ctrPhoto.photos;*/ this.reading = false; } }]); //别名:ctrPhotoDetail photogallery.controller('PhotoDetailController',$state){ }]);

以上,通过$scope.$$childTail.ctrPhotoList在父state中的controller中拿到子state中的controller;通过$scope.$parent.ctrPhoto在子state中的controller中拿到父state中的controller。

photos-list.html

rush:js;">

photos-list

pulse">
{{photo.description}}

state间如何传路由参数

在content.photos.detail这个state设置接收一个路由参数。

photos-list.html 送出一个路由参数

photos-list
heading">{{photo.title}} {{photo.description}}

以上,通过

controller.js PhotoDetailController控制器通过$stateParams获取路由参数

photos-detail.html 从以上的PhotoDetailController中获取数据。

photo-details
{{ctrPhotoDetail.photo.title}}

{{ctrPhotoDetail.photo.description}}

ottom: 15px;">

state间如何传字符串参数

在路由中这样设置:

rush:js;"> .state('content.photos.detail.comment',{ url:'/comment?skip&limit',templateUrl: 'partials/photos-detail-comment.html',controller: 'PhotoCommentController',controllerAs: 'ctrPhotoComment' })

controllers.js 中修改如下

rush:js;"> photogallery.controller('HomeController',imageName: 'image1.JPG',comments:[ { name:'User1',comment: 'Nice',imageName: 'man.png'},comment:'Very good',comment:'Nice',imageName: 'woman.png'},{ name:'User4',{ name:'User5',{ name:'User6',{ name:'User7',comment:'So so',imageName: 'man.png'} ]},imageName: 'image2.JPG',imageName: 'woman.png'} ]},imageName: 'image3.JPG',imageName: 'image4.JPG',comments:[ { name:'User6',imageName: 'man.png'} ]} ]; //给子state下controller中的photos赋值 this.pullData = function(){ $scope.$$childTail.ctrPhotoList.photos = this.photos; } }]); //别名:ctrPhotoList photogallery.controller('PhotoListController',$stateParams){ var id = null; this.photo = null; this.init = function(){ id = parseInt($stateParams.id); this.photo = $scope.ctrPhoto.photos[id]; } } ]); photogallery.controller('PhotoCommentController',$stateParams){ var id,skip,limit = null; this.comments = new Array(); this.init = function(){ id = parseInt($stateParams.id); var photo = $scope.ctrPhoto.photos[id]; if($stateParams.skip){ skip = parseInt($stateParams.skip); }else{ skip = 0; } if($stateParams.limit){ limit = parseInt($stateParams.limit); }else{ limit = photo.comments.length; } this.comments = photo.comments.slice(skip,limit); } } ]);

也就是,$stateParams不仅可以接收路由参数,还可以接收查询字符串参数。

photo-detail.html 需要把查询字符串参数传递出去

rush:js;">

photo-details

{{ctrPhotoDetail.photo.title}}

{{ctrPhotoDetail.photo.description}}

ottom: 15px;">

以上,通过ui-sref=".comment({skip:0,limit:2})把查询字符串传递出去。

photos-detail-comment.html

rush:js;">

photos-detail-comment

{{comment.comment}}

state间如何传递对象

通过data属性,把一个对象赋值给它。

给header.html加上一个对应的控制器,并提供注销方法。

添加一个有关登录页的state

添加login.html文件,现在的文件结构为:

asserts/ .....css/ .....images/ ..........image1.jpg ..........image2.jpg ..........image3.jpg ..........image4.jpg node_modules/ partials/ .....about.html .....home.html .....photos.html .....content.html .....header.html .....photos-list.html .....photo-detail.html .....photos-detail-comment.html .....login.html

app.js

index.html

login.html

header.html 修改如下

onEnter和onExit事件

rush:js;"> .state('content.photos.detail',controllerAs: 'ctrPhotoDetail',resolve:{ viewing: function($stateParams){ return{ photoId: $stateParams.id } } },onEnter: function(viewing){ var photo = JSON.parse(sessionStorage.getItem(viewing.photoId)); if(!photo){ photo = { views: 1,viewing: 1 } }else{ photo.views = photo.views + 1; photo.viewing = photo.viewing + 1; } sessionStorage.setItem(viewing.photoId,JSON.stringify(photo)); },onExit: function(viewing){ var photo = JSON.parse(sessionStorage.getItem(viewing.photoId)); photo.viewing = photo.viewing - 1; sessionStorage.setItem(viewing.photoId,JSON.stringify(photo)); } })

在PhotoDetailController中:

rush:js;"> photogallery.controller('PhotoDetailController',$stateParams){ var id = null; this.photo = null; this.viewObj = null; this.init = function(){ id = parseInt($stateParams.id); this.photo = $scope.ctrPhoto.photos[id]; this.viewObj = JSON.parse(sessionStorage.getItem($stateParams.id)); } } ]);

photos-detail.html

rush:js;">

photo-details

Views
Viewing

{{ctrPhotoDetail.photo.title}}

{{ctrPhotoDetail.photo.description}}

ottom: 15px;">

StateChangeStart事件

controller.js 增加如下

rush:js;"> photogallery.controller('RootController','$rootScope',$rootScope){ $rootScope.$on('$stateChangeStart',function(event,toState,toParams,fromState,fromParams){ if(toState.data.required && !$rootScope.user){ event.preventDefault(); $state.go('content.login'); } }); } ]);

修改content这个state:

rush:js;"> .state('content',{ url:'/',views:{ "":{ templateUrl: 'partials/content.html',controller: 'RootController' },$state){ $scope.logoff = function(){ $rootScope.user = null; } } } } })

content.photos.detail这个state

rush:js;"> .state('content.photos.detail',{ url:'/detail/:id',data:{ required: true },JSON.stringify(photo)); } })

以上,添加

rush:js;"> data:{ required: true }

同理,content.photos.detail.comment这个state

rush:js;"> .state('content.photos.detail.comment',controllerAs: 'ctrPhotoComment',data:{ required: true } })

StateNotFound事件

rush:js;"> photosgallery.controller('RootController',fromParams){ if(toState.data.required && !$rootScope.user){ event.preventDefault(); $state.go('content.login'); return; } }); $rootScope.$on('$stateNotFound',unfoundState,fromParams){ event.preventDefault(); $state.go('content.notfound'); }); } ]);

添加一个state:

rush:js;"> .state('content.notfound',{ url:'notfound',views: { "body@content": {templateUrl: 'partials/page-not-found.html'} } })

page-not-found.html

rush:js;">

404 - Sorry! Not found your page.

StateChangeSuccess事件

rush:js;"> photosgallery.controller('RootController',$rootScope){ $rootScope.accessLog = new Array(); $rootScope.$on('$stateChangeStart',fromParams){ event.preventDefault(); $state.go('content.notfound'); }); $rootScope.$on('$stateChangeSuccess',fromParams){ $rootScope.accessLog.push({ user: $rootScope.user,from: fromState.name,to: toState.name,date: new Date() }); }); } ]);

添加一个state

rush:js;"> .state('content.log',{ url:'log',views: { "body@content": {templateUrl: 'partials/log.html'} } })

log.html

rush:js;">

Access Log

{{log.user ? log.user.name: 'anonymous'}} in {{log.date | date: 'longDate'}} at {{log.date | date: 'shortTime'}}

From: {{log.from}} => to: {{log.to}}

StateChangeError事件

rush:js;"> photosgallery.controller('RootController',date: new Date() }); }); $rootScope.$on('$stateChangeError',fromParams,error){ event.preventDefault(); $state.go('content.error',{error: error}); }); } ]);

添加2个state:

rush:js;"> .state('content.profile',{ url:'profile',resolve:{ showError: function(){ throw 'Error in code.'; } },views:{ "body@content": {template: '
Error
'} } }) .state('content.error',{ url:'error/:error',views:{ "body@content":{ templateUrl: 'partials/error.html',$stateParams){ $scope.error = { message: $stateParams.error } } } } })

error.html

rush:js;">
displayed: {{error.message}}
angularjs_ui_router

相关文章

前言 做过web项目开发的人对layer弹层组件肯定不陌生,作为l...
前言 前端表单校验是过滤无效数据、假数据、有毒数据的第一步...
前言 图片上传是web项目常见的需求,我基于之前的博客的代码...
前言 导出Excel文件这个功能,通常都是在后端实现返回前端一...
前言 众所周知,js是单线程的,从上往下,从左往右依次执行,...
前言 项目开发中,我们可能会碰到这样的需求:select标签,禁...