欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Angularjs中UI Router全攻略

程序员文章站 2023-09-06 09:33:59
首先给大家介绍angular-ui-router的基本用法。 如何引用依赖angular-ui-router angular.module('app',["ui...

首先给大家介绍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大致是这样设置的:

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

所有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>