首先是angular-ui-router的基本用法。

■ 如何引用依赖angular-ui-router

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

<div ui-view></div>

$stateProvider.state("home",{template: "<h1>hi</h1>"
})

或者这样配置:

$stateProvider.state("home"{views: {"": {template: "<h1>hi</h1>"}}
})

==有名称的ui-view

<div ui-view="main"></div>

$stateProvider.state("home",{views: {"main" : {template: "<h1>hi</h1>"}}
})

==多个ui-view

<div ui-view></div>
<div ui-view="data"></div>

$stateProvider.state("home",{views: {"":{template: "<h1>hi</h1>"},"data": {template: "<div>data</div>"}}
})

■ 项目文件结构

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

■ 创建state和view

app.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

<!DOCTYPE html>
<html lang="en" ng-app="photoGallery">
<head><meta charset="UTF-8"><title></title><link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.css"/>
</head>
<body><h1>Welcome</h1><div ui-view></div><script src="node_modules/jquery/dist/jquery.js"></script><script src="node_modules/angular/angular.js"></script>
<script src="node_modules/angular-ui-router/release/angular-ui-router.js"></script>
<script src="node_modules/angular-animate/angular-animate.js"></script><script src="node_modules/bootstrap/dist/js/bootstrap.js"></script>
<script src="node_modules/angular-bootstrap/ui-bootstrap-tpls.js"></script><script src="app.js"></script>
</body>
</html>

■ state之间的跳转

index.html

<nav class="navbar navbar-inverse">
<div class="container-fluid"><div class="navbar-header"><button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button><a ui-sref="home" class="navbar-brand">Home</a></div><div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"><ul class="nav navbar-nav"><li><a ui-sref="photos">Photos</a></li><li><a ui-sref="about">About</a></li></ul></div>
</div>
</nav><div ui-view></div>

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

■ 多个view以及state嵌套

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

<div ui-view="header"></div>
<div ui-view="body"></div>

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

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

.state('content.photos',{url: 'photos',views:{"body@content":{templateUrl: 'partials/photos.html'}}
})

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

点击header对应的页面链接,可能会跳转到另外的子页面出现在<div ui-view="body"></div>这个位置。这时候页面出现了子父关系,而每个页面都属于某个state,这样state间就出现了子父关系。这些跳转的子页面,在路由设置中,可能被称为parent.son1, parent.son2...这就是state的嵌套。

在现有的文件结构上增加content.html, header.html,文件结构变为:

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

content.html 包含了多各ui-view, 一个ui-view和页头相关,保持不变;令一个ui-view和会根据页头上的点击呈现不同的内容

<div ui-view="header"></div>
<div ui-view="body"></div>

header.html 把原先indext.html中nav部分放到这里来

<nav class="navbar navbar-inverse"><div class="container-fluid"><div class="navbar-header"><button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button><a ui-sref="content.home" class="navbar-brand">Home</a></div><div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"><ul class="nav navbar-nav"><li><a ui-sref="content.photos">Photos</a></li><li><a ui-sref="content.about">About</a></li></ul></div></div>
</nav>

index.html 这时变成了这样

<div ui-view></div>

app.js 路由现在这样设置

var photoGallery = angular.module('photoGallery',["ui.router"]);photoGallery.config(function($stateProvider, $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这个路由

.state('content.home',{url: 'home',views:{"body@content":{templateUrl: 'partials/home.html'}}
})

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

→ 路由看到index.html上的<div ui-view></div>

.state('content',{url: '/',views:{"":{templateUrl: 'partials/content.html'},"header@content":{templateUrl: 'partials/header.html'},}
})

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

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

看到<div ui-view="header"></div>,就加载如下:

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

看到<div ui-view="body"></div>,先加载 "body@content":{templateUrl: 'partials/home.html'}

→ 点击header上的链接

点击<a ui-sref="content.photos">Photos</a>,来到:

.state('content.photos',{url: 'photos',views:{"body@content":{templateUrl: 'partials/photos.html'}}
})

把partials/photos.html显示到<div ui-view="body"></div>中去。

点击<div ui-view="body"></div>,来到:

.state('content.about',{url:'about',views:{"body@content":{templateUrl: 'partials/about.html'}}
})

把partials/about.html显示到<div ui-view="body"></div>中去。

■ 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
<div ui-view></div>

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

<nav class="navbar navbar-inverse"><div class="container-fluid"><div class="navbar-header"><button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button><a ui-sref="content.home" class="navbar-brand">Home</a></div><div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"><ul class="nav navbar-nav"><li><a ui-sref="content.photos.list">Photos</a></li><li><a ui-sref="content.about">About</a></li></ul></div></div>

以上,通过<a ui-sref="content.photos.list">Photos</a>来到photos.html的子页面photos-list.html.

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

<h1>photos-list</h1>
<ul><li><a ui-sref="^.detail">我通过相对路径到相邻的state</a></li><li><a ui-sref="content.photos.detail">我通过绝对路径到相邻的state</a></li>
</ul>

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

<h1>photo-details</h1>
<a class="btn btn-default" ui-sref=".comment">通过相对路径去子state</a>
<div ui-view></div>

photos-detail-comment.html 则很简单:
<h1>photos-detail-comment</h1>

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

var photoGallery = angular.module('photoGallery',["ui.router"]);photoGallery.config(function($stateProvider, $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.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',{url:'about',views:{"body@content":{templateUrl: 'partials/about.html'}}})
})

■ 抽象state

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

.state('content',{url: '/',abstract: true,views:{"":{templateUrl: 'partials/content.html'},"header@content":{templateUrl: 'partials/header.html'},}
})
....state('content.photos',{url: 'photos',abstract: true,views:{"body@content":{templateUrl: 'partials/photos.html'}}
})

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

--会导航到默认路由上

$urlRouterProvider.otherwise('home');

.state('content.home',{url: 'home',views:{"body@content":{templateUrl: 'partials/home.html'}}
})

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

■ 使用控制器

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

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

var photoGallery = angular.module('photoGallery',["ui.router"]);photoGallery.config(function($stateProvider, $urlRouterProvider){$urlRouterProvider.otherwise('home');$stateProvider.state('content',{url: '/',abstract: true,views:{"":{templateUrl: 'partials/content.html'},"header@content":{templateUrl: 'partials/header.html'},}}).state('content.home',{url: 'home',views:{"body@content":{templateUrl: 'partials/home.html',controller: 'HomeController',controllerAs: 'ctrHome'}}}).state('content.photos',{url: 'photos',abstract: true,views:{"body@content":{templateUrl: 'partials/photos.html',controller: 'PhotoController',controllerAs: 'ctrPhoto'}}}).state('content.photos.list',{url: '/list',templateUrl: 'partials/photos-list.html',controller: "PhotoListController",controllerAs: 'ctrPhotoList'}).state('content.photos.detail',{url: '/detail',templateUrl: 'partials/photos-detail.html',controller: 'PhotoDetailController',controllerAs: 'ctrPhotoDetail'}).state('content.photos.detail.comment',{url: '/comment',templateUrl: 'partials/photos-detail-comment.html'}).state('content.about',{url:'about',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

photoGallery.controller('HomeController',['$scope', '$state', function($scope, $state){this.message = 'Welcome to the Photo Gallery';
}]);//别名:ctrPhoto
photoGallery.controller('PhotoController',['$scope','$state', function($scope, $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', comment: 'Nice'},{ name:'User1', comment:'Very good'}]},{ id: 2, title: 'Photo 3', description: 'description for photo 3', imageName: 'image3.jpg', comments:[{name: 'user1', comment: 'Nice'}]},{ id: 3, title: 'Photo 4', description: 'description for photo 4', imageName: 'image4.jpg', comments:[{name: 'user1', comment: 'Nice'},{ name:'User2', comment:'Very good'},{ name:'User3', comment:'So so'}]}];//给子state下controller中的photos赋值this.pullData = function(){$scope.$$childTail.ctrPhotoList.photos = this.photos;}
}]);//别名:ctrPhotoList
photoGallery.controller('PhotoListController',['$scope','$state', function($scope, $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',['$scope', '$state', function($scope,$state){}]);

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

photos-list.html

<h1>photos-list</h1>
<div ng-init="ctrPhotoList.init()"><div style="margin:auto; width: 40px;" ng-if="ctrPhotoList.reading"><i class="fa fa-spinner fa-5x fa-pulse"></i></div><div class="well well-sm" ng-repeat="photo in ctrPhotoList.photos"><div class="media"><div class="media-left" style="width:15%;"><a ui-sref="content.photos.detail"><img class="img-responsive img-rounded" src="../asserts/images/{{photo.imageName}}" alt=""></a></div><div class="media-body"><h4 class="media-heading">{{photo.title}}</h4>{{photo.description}}</div></div></div>
</div>

■ state间如何传路由参数

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

.state('content.photos.detail',{url: '/detail/:id',templateUrl: 'partials/photos-detail.html',controller: 'PhotoDetailController',controllerAs: 'ctrPhotoDetail'
})

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

<h1>photos-list</h1>
<div ng-init="ctrPhotoList.init()"><div style="margin:auto; width: 40px;" ng-if="ctrPhotoList.reading"><i class="fa fa-spinner fa-5x fa-pulse"></i></div><div class="well well-sm" ng-repeat="photo in ctrPhotoList.photos"><div class="media"><div class="media-left" style="width:15%;"><a ui-sref="content.photos.detail({id:photo.id})"><img class="img-responsive img-rounded" src="../asserts/images/{{photo.imageName}}" alt=""></a></div><div class="media-body"><h4 class="media-heading">{{photo.title}}</h4>{{photo.description}}</div></div></div>
</div>

以上,通过<a ui-sref="content.photos.detail({id:photo.id})">把路由参数送出。

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

...
//别名:ctrPhotoDetail
photosGallery.controller('PhotoDetailController', ['$scope', '$state', '$stateParams',function($scope, $state, $stateParams){var id = null;this.photo = null;this.init = function(){id = parseInt($stateParams.id);this.photo = $scope.ctrPhoto.photos[id];}}
]);

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

<h1>photo-details</h1>
<a class="btn btn-default" ui-sref=".comment">通过相对路径去子state</a>
<a ui-sref="content.photos.list" style="margin-left: 15px;"><i class="fa fa-arrow-circle-left fa-2x"></i>
</a><div ng-init="ctrPhotoDetail.init()"><img class="img-responsive img-rounded" ng-src="../assets/images/{{ctrPhotoDetail.photo.imageName}}"style="margin:auto; width: 60%;"><div class="well well-sm" style="margin:auto; width: 60%; margin-top: 15px;"><h4>{{ctrPhotoDetail.photo.title}}</h4><p>{{ctrPhotoDetail.photo.description}}</p></div><div style="margin:auto; width: 80%; margin-bottom: 15px;"><button style="margin-top: 10px; width:100%;"class="btn btn-default" ui-sref=".comment">Comments</button></div>
</div><div ui-view></div>

■ state间如何传字符串参数

在路由中这样设置:

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

controllers.js 中修改如下

photoGallery.controller('HomeController',['$scope', '$state', function($scope, $state){this.message = 'Welcome to the Photo Gallery';
}]);//别名:ctrPhoto
photoGallery.controller('PhotoController',['$scope','$state', function($scope, $state){this.photos = [{ id: 0, title: 'Photo 1', description: 'description for photo 1', imageName: 'image1.JPG', comments:[{ name:'User1', comment: 'Nice', imageName: 'man.png'},{ name:'User2', comment:'Very good', imageName: 'man.png'},{ name:'User3', comment:'Nice', imageName: 'woman.png'},{ name:'User4', comment:'Very good', imageName: 'woman.png'},{ name:'User5', comment:'Very good', imageName: 'man.png'},{ name:'User6', comment:'Nice', imageName: 'woman.png'},{ name:'User7', comment:'So so', imageName: 'man.png'}]},{ id: 1, title: 'Photo 2', description: 'description for photo 2', imageName: 'image2.JPG', comments:[{ name:'User1', comment: 'Nice', imageName: 'man.png'},{ name:'User2', comment:'Very good', imageName: 'man.png'},{ name:'User3', comment:'Nice', imageName: 'woman.png'},{ name:'User4', comment:'Very good', imageName: 'woman.png'}]},{ id: 2, title: 'Photo 3', description: 'description for photo 3', imageName: 'image3.JPG', comments:[{ name:'User1', comment: 'Nice', imageName: 'man.png'},{ name:'User2', comment:'Very good', imageName: 'man.png'},{ name:'User3', comment:'Nice', imageName: 'woman.png'},{ name:'User4', comment:'Very good', imageName: 'woman.png'},{ name:'User5', comment:'Very good', imageName: 'man.png'},{ name:'User6', comment:'Nice', imageName: 'woman.png'},{ name:'User7', comment:'So so', imageName: 'man.png'}]},{ id: 3, title: 'Photo 4', description: 'description for photo 4', imageName: 'image4.JPG', comments:[{ name:'User6', comment:'Nice', imageName: 'woman.png'},{ name:'User7', comment:'So so', imageName: 'man.png'}]}];//给子state下controller中的photos赋值this.pullData = function(){$scope.$$childTail.ctrPhotoList.photos = this.photos;}
}]);//别名:ctrPhotoList
photoGallery.controller('PhotoListController',['$scope','$state', function($scope, $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', ['$scope', '$state', '$stateParams',function($scope, $state, $stateParams){var id = null;this.photo = null;this.init = function(){id = parseInt($stateParams.id);this.photo = $scope.ctrPhoto.photos[id];}}
]);photoGallery.controller('PhotoCommentController', ['$scope', '$state', '$stateParams',function($scope, $state, $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 需要把查询字符串参数传递出去

<h1>photo-details</h1>
<a class="btn btn-default" ui-sref=".comment">通过相对路径去子state</a>
<a ui-sref="content.photos.list" style="margin-left: 15px;"><i class="fa fa-arrow-circle-left fa-2x"></i>
</a><div ng-init="ctrPhotoDetail.init()"><img class="img-responsive img-rounded" ng-src="../assets/images/{{ctrPhotoDetail.photo.imageName}}"style="margin:auto; width: 60%;"><div class="well well-sm" style="margin:auto; width: 60%; margin-top: 15px;"><h4>{{ctrPhotoDetail.photo.title}}</h4><p>{{ctrPhotoDetail.photo.description}}</p></div><div style="margin:auto; width: 80%; margin-bottom: 15px;"><button style="margin-top: 10px; width:100%;"class="btn btn-default" ui-sref=".comment({skip:0, limit:2})">Comments</button></div>
</div><div ui-view></div>

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

photos-detail-comment.html

<h1>photos-detail-comment</h1><div ng-init="ctrPhotoComment.init()" style="margin-top:15px;"><div ng-repeat="comment in ctrPhotoComment.comments" class="well well-sm" style="margin: auto; width: 60%;"><div class="media"><div class="media-left media-middle"><a href=""><img class="img-circle" style="width:60px;" src="../assets/images/{{comment.imageName}}" alt=""></a></div><div class="media-body"><h4 class="media-heading">{{comment.name}}</h4>{{comment.comment}}</div></div></div>
</div>

■ state间如何传递对象

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

.state('content',{url: '/',abstract: true,data:{user: "user",password: "1234"},views:{"":{templateUrl: 'partials/content.html'},"header@content":{templateUrl: 'partials/header.html'},}
})

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

$stateProvider.state('content',{url: '/',abstract: true,data:{user: "user",password: "1234"},views:{"":{templateUrl: 'partials/content.html'},"header@content":{templateUrl: 'partials/header.html',controller: function($scope, $rootScope, $state){$scope.logoff = function(){$rootScope.user = null;}}}}})

添加一个有关登录页的state

.state('content.login',{url:'login',data:{loginError: 'User or password incorrect.'},views:{"body@content" :{templateUrl: 'partials/login.html',controller: function($scope, $rootScope, $state){$scope.login = function(user, password, valid){if(!valid){return;}if($state.current.data.user === user && $state.current.data.password === password){$rootScope.user = {name: $state.current.data.user}// Or Inherited/*$rootScope.user = {name: $state.$current.parent.data.user};*/$state.go('content.home');                            }else{$scope.message = $state.current.data.loginError;}}}}}})

添加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

<form name="form" ng-submit="login(user, password, form.$valid)"><div class="panel panel-primary" style="width:360px; margin: auto;"><div class="panel-heading"><h3 class="panel-title">Indentification</h3></div><div class="panel-body"><input name="user" type="text" class="form-control" ng-model="user" placeholder="User ..." required><span ng-show="form.user.$error.required && form.user.$dirty" class="label label-danger">Enter the user</span><hr><input name="password" type="password" class="form-control" ng-model="password" placeholder="Password ..." required><span ng-show="form.password.$error.required && form.password.$dirty" class="label label-danger">Enter the password</span>            </div><div class="panel-footer"><button class="btn btn-default" type="submit">Login</button><button class="btn btn-default" type="reset">Reset</button><span class="label label-danger">{{message}}</span>            </div>    </div>
</form>

header.html 修改如下

<nav class="navbar navbar-inverse"><div class="container-fluid"><div class="navbar-header"><button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">            <span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button><a class="navbar-brand" ui-sref="content.home">Home</a></div><div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"><ul class="nav navbar-nav"><li><a ui-sref="content.photos.list">Photos</a>    </li><li><a ui-sref="content.about">About</a>    </li> </ul><ul class="nav navbar-nav navbar-right">                <li ng-if="user.name" class="dropdown"><a class="dropdown-toggle" role="button" aria-expanded="false" href="#" data-toggle="dropdown">{{user.name}} <span class="caret"></span></a><ul class="dropdown-menu" role="menu"><li><a ui-sref="content.home" ng-click="logoff()">Sing out</a></li>                        </ul>                    </li>                                <li ng-if="!user.name"><a ui-sref="content.login">Sing In</a></li>                    </ul>    </div></div></nav>

■ onEnter和onExit事件

.state('content.photos.detail',{url: '/detail/:id',templateUrl: 'partials/photos-detail.html',controller: 'PhotoDetailController',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中:

photoGallery.controller('PhotoDetailController', ['$scope', '$state', '$stateParams',function($scope, $state, $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

<h1>photo-details</h1>
<a class="btn btn-default" ui-sref=".comment">通过相对路径去子state</a>
<a ui-sref="content.photos.list" style="margin-left: 15px;"><i class="fa fa-arrow-circle-left fa-2x"></i>
</a><div ng-init="ctrPhotoDetail.init()"><img class="img-responsive img-rounded" ng-src="../assets/images/{{ctrPhotoDetail.photo.imageName}}"style="margin:auto; width: 60%;"><div class="well well-sm" style="margin:auto; width: 60%; margin-top: 15px;"><div class="well well-sm pull-right" style="width: 100px;"><i>Views <span class="badge">{{ctrPhotoDetail.viewObj.views}}</span></i></div><div class="well well-sm pull-right" style="width: 110px;"><i>Viewing <span class="badge">{{ctrPhotoDetail.viewObj.viewing}}</span></i></div><h4>{{ctrPhotoDetail.photo.title}}</h4><p>{{ctrPhotoDetail.photo.description}}</p></div><div style="margin:auto; width: 80%; margin-bottom: 15px;"><button style="margin-top: 10px; width:100%;"class="btn btn-default" ui-sref=".comment({skip:0, limit:2})">Comments</button></div>
</div><div ui-view></div>

■ StateChangeStart事件

controller.js 增加如下

photoGallery.controller('RootController', ['$scope', '$state', '$rootScope',function($scope, $state, $rootScope){$rootScope.$on('$stateChangeStart',function(event, toState, toParams, fromState, fromParams){if(toState.data.required && !$rootScope.user){event.preventDefault();$state.go('content.login');}});}
]);

修改content这个state:

.state('content',{url:'/',abstract: true,data:{user: "user",password: "1234"},views:{"":{templateUrl: 'partials/content.html',controller: 'RootController'},"header@content":{templateUrl: 'partials/header.html',controller: function($scope, $rootScope, $state){$scope.logoff = function(){$rootScope.user = null;}}}}})

content.photos.detail这个state

    .state('content.photos.detail',{url:'/detail/:id',templateUrl: 'partials/photos-detail.html',controller: 'PhotoDetailController',controllerAs: 'ctrPhotoDetail',data:{required: true},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));}})

以上,添加了        
data:{
    required: true
}

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

.state('content.photos.detail.comment',{url:'/comment?skip&limit',templateUrl: 'partials/photos-detail-comment.html',controller: 'PhotoCommentController',controllerAs: 'ctrPhotoComment',data:{required: true}})

■ StateNotFound事件

photosGallery.controller('RootController', ['$scope', '$state', '$rootScope',function($scope, $state, $rootScope){$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){if(toState.data.required && !$rootScope.user){event.preventDefault();$state.go('content.login');return;}    });$rootScope.$on('$stateNotFound', function(event, unfoundState, fromState, fromParams){event.preventDefault();$state.go('content.notfound');});}
]);

添加一个state:

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

page-not-found.html

<div class="well well-sm" style="margin: 20px;"><i class="fa fa-frown-o fa-4x pull-left"></i><h3>404 - Sorry! Not found your page.</h3>
</div>

■ StateChangeSuccess事件

photosGallery.controller('RootController', ['$scope', '$state', '$rootScope',function($scope, $state, $rootScope){$rootScope.accessLog = new Array();$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){if(toState.data.required && !$rootScope.user){event.preventDefault();$state.go('content.login');return;}    });$rootScope.$on('$stateNotFound', function(event, unfoundState, fromState, fromParams){event.preventDefault();$state.go('content.notfound');});$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){$rootScope.accessLog.push({user: $rootScope.user,from: fromState.name,to: toState.name,date: new Date()});});}
]);

添加一个state

    .state('content.log',{url:'log',data:{required: true},views: {"body@content": {templateUrl: 'partials/log.html'}    }        })

log.html

<h1><i class="fa fa-file-text-o"></i> Access Log</h1>
<div style="margin:auto; width: 380px;"><div class="well well-sm" ng-repeat="log in accessLog track by $index"><i class="fa fa-pencil fa-2x pull-left"></i>{{log.user ? log.user.name: 'anonymous'}} in {{log.date | date: 'longDate'}} at {{log.date | date: 'shortTime'}}<p>From: {{log.from}} => to: {{log.to}}</p></div>
</div>

■ StateChangeError事件

photosGallery.controller('RootController', ['$scope', '$state', '$rootScope',function($scope, $state, $rootScope){$rootScope.accessLog = new Array();$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){if(toState.data.required && !$rootScope.user){event.preventDefault();$state.go('content.login');return;}    });$rootScope.$on('$stateNotFound', function(event, unfoundState, fromState, fromParams){event.preventDefault();$state.go('content.notfound');});$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){$rootScope.accessLog.push({user: $rootScope.user,from: fromState.name,to: toState.name,date: new Date()});});$rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error){event.preventDefault();$state.go('content.error', {error: error});});}
]);

添加2个state:

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

error.html

<div class="well well-sm" style="margin: 20px;"><i class="fa fa-exclamation-circle fa-2x"> Sorry! But this message was displayed: {{error.message}}</i>
</div>

转载于:https://www.cnblogs.com/darrenji/p/5167999.html

AngularJS中ui-router全攻略相关推荐

  1. 一份超详细的UI设计规范全攻略

    01 如何去做? 根据原子定律(不懂原子定律同学可以搜索原子设计方法)我们从页面中最细小的元素入手,也可以理解为页面中无法再拆分的元素开始,它是组成界面最基础的元素,从最基础的元素,开始做统一性,本次 ...

  2. sas数字转日期格式_SAS中日期转换全攻略

    (转) 在SAS处理中,特别是在多个数据集合并过程中,我们经常要遇到 日期格式不匹配的情况,但是 日期 又是一个非常关键的 匹配关键词,所以有必要 将各种不同的 日期变量的 转化 方法在这里做一个总结 ...

  3. sas数字转日期格式_[转载]SAS中日期转换全攻略

    以下的内容,要感谢 webgu 在人大论坛上的亲情奉献. 在SAS处理中,特别是在多个数据集合并过程中,我们经常要遇到 日期格式不匹配的情况,但是 日期 又是一个非常关键的 匹配关键词,所以有必要 将 ...

  4. DBGRIDEH 组件在Borland开发工具中应用全攻略

    DBGRIDEH 组件在Borland开发工具中应用全攻略         2003-08-05 16:36:18     陈文彬     DBGRIDEH 是Enlib 3.0组件包中的组件之一.E ...

  5. 企业上云要几步?中拓互联奉送企业上云全攻略

    企业上云要几步?中拓互联奉送企业上云全攻略 不论是国家倡导的"上云用数赋智",还是由疫情引发的强烈需求,这两年成长型企业上云,可谓是如火如荼. 图片来源于:人民政府网 虚无缥缈的一 ...

  6. UI设计中个人页面设计攻略

    最近刚做完一个项目,我发现我的设计效率相比之前竟然提升了30%以上,在以前做界面时总是会纠结采用什么样式,什么布局.而现在再看了原型之后就大概知道我要怎么做了,没有了以前做页面时的纠结,效率自然提升了 ...

  7. 《电脑音乐制作实战指南:伴奏、录歌、MTV全攻略》——2.7 消除歌曲中某个合音或乐器...

    本节书摘来自异步社区<电脑音乐制作实战指南:伴奏.录歌.MTV全攻略>一书中的第2章,第2.7节,作者 健逗,更多章节内容可以访问云栖社区"异步社区"公众号查看. 2. ...

  8. 电影下载全攻略 [初、中、高级]——老猫

    电影下载全攻略 [初.中.高级]--老猫 初级篇 出于保护版权的目的,RM和ASF这两种格式文件的播放器--RealPlay和MediaPlayer都没有提供SAVE AS选项.如果希望看完节目后在w ...

  9. 财务软件、进销存软件、ERP中会计凭证录入模块DIY全攻略

    财务软件.进销存软件.ERP中会计凭证录入模块DIY全攻略(二) 一.需求分析   1.录入界面要求友好,直观便捷,提供多种录入途径并有容错设计:   2.凭证录入要符合现行会计制度的要求,制度规定的 ...

  10. 口袋超萌服务器维护中,平民全攻略1

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 平民全攻略 等级篇:每天商店买4个体力和限时抢购里全部体力,冲等级,有些人说到70级级就可以了,我建议到80级才停,为什么?因为等级高,每周日排名结算时钻 ...

最新文章

  1. 锐捷云课堂助力海南农垦中学 根治计算机教室“老病根”
  2. c语言中 %s 占几个字节,printf(%*s%s%*s,——)是什么?
  3. 促销海报设计模板,可临摹学习!
  4. MVVM绑定多层级数据到TreeView并设置项目展开
  5. JavaScript 图片切换展示效果
  6. 【Visual C++】Windows GDI贴图闪烁解决方法
  7. (11)机器学习_Kmeans聚类算法
  8. 怎么在小芭比Puppy Linux中文版中集成软件
  9. vs2003无法打开sal.h
  10. ong拼音汉字_汉语拼音ong的发音方法
  11. 主动学习,半监督学习,直推式学习
  12. Ubuntu上开发python的十大IDE
  13. 两行代码实现微信电脑版多开
  14. 文氏图解析SQL语句中JOIN操作
  15. android计算器退格键,请问下计算器的退格键是哪个键?
  16. [读书笔记]《番茄工作法图解:简单易行的时间管理方法》
  17. 明日之后mumu模拟器找不到服务器,MuMu模拟器玩明日之后常见问题汇总
  18. LeetCode 13 罗马符号转化为数字(难度: Easy)
  19. 牛客剪刀石头布Java 模拟+贪心
  20. 如何对市场进行深入了解,了解当前市场上的热销产品、消费者需求以及行业发展趋势?在哪里寻找专业报告、行业数据、市场分析文章等?

热门文章

  1. 使用Http协议访问网络--HttpClient
  2. python冒泡排序函数_python冒泡排序-Python,冒泡排序
  3. python蟒蛇代码_011 实例2-Python蟒蛇绘制
  4. Codeforces - 102222C - Caesar Cipher
  5. LuoguP1268树的重量【构造/思维】By cellur925
  6. uiautomator的坑和AAPT命令方式启动一个应用程序
  7. LinkedHashMap 根据PUT顺序排序Map
  8. MySQL与PostgreSQL:该选择哪个开源数据库?哪一个更好?
  9. java懒加载设计模式_java设计模式——单例模式
  10. 系统间数据传输,产品经理视角的9千字总结:接口、otter、log4j、SFTP、MQ……