Angularjs中UI Router全攻略


Posted in Javascript onJanuary 29, 2016

首先给大家介绍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>
Javascript 相关文章推荐
使用JQuery和s3captche实现一个水果名字的验证
Aug 14 Javascript
通过JS自动隐藏手机浏览器的地址栏实现原理与代码
Jan 02 Javascript
jquery实现带复选框的表格行选中删除时高亮显示
Aug 01 Javascript
Jquery实现textarea根据文本内容自适应高度
Apr 03 Javascript
JS模式之简单的订阅者和发布者模式完整实例
Jun 30 Javascript
jquery实现树形菜单完整代码
Dec 29 Javascript
javascript实现起伏的水波背景效果
May 16 Javascript
详解javascript中对数据格式化的思考
Jan 23 Javascript
JS三目运算(三元运算)方法详解
Mar 01 Javascript
微信小程序实现左右联动的实战记录
Jul 05 Javascript
基于游标的分页接口实现代码示例
Nov 12 Javascript
vue-preview动态获取图片宽高并增加旋转功能的实现
Jul 29 Javascript
JavaScript数据结构与算法之集合(Set)
Jan 29 #Javascript
AngularJS 使用 UI Router 实现表单向导
Jan 29 #Javascript
JavaScript数据结构与算法之链表
Jan 29 #Javascript
动态创建按钮的JavaScript代码
Jan 29 #Javascript
JavaScript数据结构与算法之栈与队列
Jan 29 #Javascript
javascript实现表单验证
Jan 29 #Javascript
jQuery实现横向带缓冲的水平运动效果(附demo源码下载)
Jan 29 #Javascript
You might like
PHP 各种排序算法实现代码
2009/08/20 PHP
PHP管理依赖(dependency)关系工具 Composer 安装与使用
2014/08/18 PHP
基于PHP给大家讲解防刷票的一些技巧
2015/11/18 PHP
CI框架整合smarty步骤详解
2016/05/19 PHP
PHP中的正则表达式实例详解
2017/04/25 PHP
php校验公钥是否可用的实例方法
2019/09/17 PHP
Javascript 阻止javascript事件冒泡,获取控件ID值
2009/06/27 Javascript
javascript 当前日期加(天、周、月、年)
2009/08/09 Javascript
基于jquery的一行代码轻松实现拖动效果
2010/12/28 Javascript
node.js中的buffer.toString方法使用说明
2014/12/14 Javascript
jquery代码实现简单的随机图片瀑布流效果
2015/04/20 Javascript
jquery带有索引按钮且自动轮播切换特效代码分享
2015/09/15 Javascript
jQuery检测滚动条是否到达底部
2015/12/15 Javascript
angular2使用简单介绍
2016/03/01 Javascript
JavaScript中循环遍历Array与Map的方法小结
2016/03/12 Javascript
jQuery Ajax和getJSON获取后台普通json数据和层级json数据用法分析
2016/06/08 Javascript
webpack入门+react环境配置
2017/02/08 Javascript
深入学习 JavaScript中的函数调用
2017/03/23 Javascript
vue如何使用 Slot 分发内容实例详解
2017/09/05 Javascript
基于jquery实现五星好评
2017/11/18 jQuery
关于Vue在ie10下空白页的debug小结
2018/05/02 Javascript
详解React之key的使用和实践
2018/09/29 Javascript
jQuery判断自定义属性data-val用法示例
2019/01/07 jQuery
Vue中UI组件库之Vuex与虚拟服务器初识
2019/05/07 Javascript
[03:11]DOTA2上海特锦赛小组赛第一日recap精彩回顾
2016/02/28 DOTA
Python生成随机MAC地址
2015/03/10 Python
Spring实战之使用util:命名空间简化配置操作示例
2019/12/09 Python
css3 旋转按钮 使用CSS3创建一个旋转可变色按钮
2012/12/31 HTML / CSS
mysql有关权限的表都有哪几个
2015/04/22 面试题
党支部对照检查材料
2014/08/25 职场文书
白酒代理协议书范本
2014/10/26 职场文书
2014年幼儿园学期工作总结
2014/12/05 职场文书
秦兵马俑导游词
2015/02/02 职场文书
让世界充满爱观后感
2015/06/10 职场文书
环境卫生整治简报
2015/07/20 职场文书
诚信考试主题班会
2015/08/17 职场文书