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 相关文章推荐
javascript 读取图片文件的大小
Jun 25 Javascript
JQuery获取文本框中字符长度的代码
Sep 29 Javascript
Jquery读取URL参数小例子
Aug 30 Javascript
JS 获取鼠标左右键的键值方法
Oct 11 Javascript
JavaScript中的setUTCDate()方法使用详解
Jun 11 Javascript
基于vue.js实现图片轮播效果
Dec 01 Javascript
Bootstrap CSS组件之导航(nav)
Dec 17 Javascript
深入理解 JavaScript 中的 JSON
Apr 06 Javascript
详谈js使用in和hasOwnProperty获取对象属性的区别
Apr 25 Javascript
基于jstree使用AJAX请求获取数据形成树
Aug 29 Javascript
iview tabs 顶部导航栏和模块切换栏的示例代码
Mar 04 Javascript
pm2发布node配置文件ecosystem.json详解
May 15 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
ASP和PHP都是可以删除自身的
2007/04/09 PHP
PHP程序员面试 切忌急功近利(更需要注重以后的发展)
2010/09/01 PHP
PHP中限制IP段访问、禁止IP提交表单的代码
2011/04/23 PHP
php密码生成类实例
2014/09/24 PHP
php+mysql实现数据库随机重排实例
2014/10/17 PHP
php单态设计模式(单例模式)实例
2014/11/18 PHP
使用xampp搭建运行php虚拟主机的详细步骤
2015/10/21 PHP
CI框架(CodeIgniter)操作redis的方法详解
2018/01/25 PHP
基于JQUERY的两个ListBox子项互相调整的实现代码
2011/05/07 Javascript
jquery 年会抽奖程序
2011/12/22 Javascript
jQuery+ajax实现鼠标单击修改内容的思路
2014/06/29 Javascript
jQuery向后台传入json格式数据的方法
2015/02/13 Javascript
学习使用AngularJS文件上传控件
2016/02/16 Javascript
关于input全选反选恶心的异常情况
2016/07/24 Javascript
wap手机端解决返回上一页的js实例
2016/12/08 Javascript
Jquery EasyUI Datagrid右键菜单实现方法
2016/12/30 Javascript
学好js,这些js函数概念一定要知道【推荐】
2017/01/19 Javascript
详解vue填坑之解决部分浏览器不支持pushState方法
2018/07/12 Javascript
vue.js指令v-for使用以及下标索引的获取
2019/01/31 Javascript
vue项目初始化到登录login页面的示例
2019/10/31 Javascript
JavaScript Window浏览器对象模型原理解析
2020/05/30 Javascript
Vue实现计算器计算效果
2020/08/17 Javascript
Python中Selenium模拟JQuery滑动解锁实例
2017/07/26 Python
Python实现读写INI配置文件的方法示例
2018/06/09 Python
python批量复制图片到另一个文件夹
2018/09/17 Python
对Python 语音识别框架详解
2018/12/24 Python
Python设计模式之装饰模式实例详解
2019/01/21 Python
Python中的相关分析correlation analysis的实现
2019/08/29 Python
Django实现文件上传下载
2019/10/06 Python
超市实习总结自我鉴定
2013/09/19 职场文书
养殖人员的创业计划书范文
2013/12/26 职场文书
安全大检查实施方案
2014/02/22 职场文书
离婚纠纷代理词
2015/05/23 职场文书
优秀学生主要事迹怎么写
2015/11/04 职场文书
2016大学生形势与政策心得体会
2016/01/12 职场文书
创业计划书之蛋糕店
2019/08/29 职场文书