Angularjs中UI Router全攻略
首先給大家介紹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可以為空對(duì)象
$stateProvider.state("home",{});
//state可以有子父級(jí)
$stateProvider.state("home",{});
$stateProvider.state("home.child",{})
//state可以是鏈?zhǔn)降?br />
$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類型,必須,使用"^"或"."表示相對(duì)路徑;
形參toParams可空,類型是對(duì)象;
形參options可空,類型是對(duì)象,字段包括:location為bool類型默認(rèn)true,inherit為bool類型默認(rèn)true, relative為對(duì)象默認(rèn)$state.$current,notify為bool類型默認(rèn)為true, reload為bool類型默認(rèn)為false
$state.go('photos.detail')
$state.go('^')到上一級(jí),比如從photo.detail到photo
$state.go('^.list')到相鄰state,比如從photo.detail到photo.list
$state.go('^.detail.comment')到孫子級(jí)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>"
}
}
})
==多個(gè)ui-view
<div ui-view></div>
<div ui-view="data"></div>
$stateProvider.state("home",{
views: {
"":{template: "<h1>hi</h1>"},
"data": {template: "<div>data</div>"}
}
})
項(xiàng)目文件結(jié)構(gòu)
node_modules/
partials/
.....about.html
.....home.html
.....photos.html
app.js
index.html
創(chuàng)建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之間的跳轉(zhuǎn)
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之間的跳轉(zhuǎn)。
多個(gè)view以及state嵌套
有時(shí)候,一個(gè)頁面上可能有多個(gè)ui-view,比如:
<div ui-view="header"></div> <div ui-view="body"></div>
假設(shè),以上頁面屬于一個(gè)名稱為parent的state中。
我們知道在ui-router中,一個(gè)state大致是這樣設(shè)置的:
<div ui-view="header"></div> <div ui-view="body"></div>
所有state下views下的所有鍵值對(duì)(類似 "body@content":{templateUrl: 'partials/photos.html'})都被放到一個(gè)鍵值集合中。而ui-view的工作原理就是根據(jù)自己的屬性值,到這個(gè)鍵值集合中去找匹配的鍵,找到就把對(duì)應(yīng)的頁面顯示出來。
點(diǎn)擊header對(duì)應(yīng)的頁面鏈接,可能會(huì)跳轉(zhuǎn)到另外的子頁面出現(xiàn)在<div ui-view="body"></div>這個(gè)位置。這時(shí)候頁面出現(xiàn)了子父關(guān)系,而每個(gè)頁面都屬于某個(gè)state,這樣state間就出現(xiàn)了子父關(guān)系。這些跳轉(zhuǎn)的子頁面,在路由設(shè)置中,可能被稱為parent.son1, parent.son2...這就是state的嵌套。
在現(xiàn)有的文件結(jié)構(gòu)上增加content.html, header.html,文件結(jié)構(gòu)變?yōu)椋?/p>
node_modules/
partials/
.....about.html
.....home.html
.....photos.html
.....content.html
.....header.html
app.js
index.html
content.html 包含了多各ui-view, 一個(gè)ui-view和頁頭相關(guān),保持不變;令一個(gè)ui-view和會(huì)根據(jù)頁頭上的點(diǎn)擊呈現(xiàn)不同的內(nèi)容
<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 這時(shí)變成了這樣
<div ui-view></div>
app.js 路由現(xiàn)在這樣設(shè)置
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'}
}
})
})
這時(shí)候,頁面是這樣呈現(xiàn)出來的:
→ 來到home這個(gè)路由
.state('content.home',{
url: 'home',
views:{
"body@content":{templateUrl: 'partials/home.html'}
}
})
以上,告訴我們partials/home.html將會(huì)被加載到與"body@content"匹配的ui-view中。暫時(shí)對(duì)應(yīng)的ui-view還沒有出現(xiàn),于是等待。
→ 路由看到index.html上的<div ui-view></div>
.state('content',{
url: '/',
views:{
"":{templateUrl: 'partials/content.html'},
"header@content":{templateUrl: 'partials/header.html'},
}
})
于是,就找到了content這個(gè)state下views下的 "":{templateUrl: 'partials/content.html'}這個(gè)鍵值對(duì),把partials/content.html顯示出來。
→ 分別加載partials/content.html頁面上的各個(gè)部分
看到<div ui-view="header"></div>,就加載如下:
"header@content":{templateUrl: 'partials/header.html'},
看到<div ui-view="body"></div>,先加載 "body@content":{templateUrl: 'partials/home.html'}
→ 點(diǎn)擊header上的鏈接
點(diǎn)擊<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>中去。
點(diǎn)擊<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多級(jí)嵌套
以上,在路由設(shè)置中,state名稱有content, content.photos有了這樣的一層嵌套。接下來,要實(shí)現(xiàn)state的多級(jí)嵌套。
在photos.html頁面準(zhǔn)備加載一個(gè)子頁面,叫做photos-list.html;
與photo-list.html頁面相鄰的還有一個(gè)頁面,叫做photo-detail.html;
在photo-detail.html頁面上加載一個(gè)子頁面,叫做photos-detail-comment.html;
這樣,頁面有了嵌套關(guān)系,state也相應(yīng)的會(huì)有嵌套關(guān)系。
現(xiàn)在,文件結(jié)構(gòu)變成:
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 加一個(gè)容納子頁面的ui-view
photos
<div ui-view></div>
如何到達(dá)這個(gè)子頁面呢?修改header中的相關(guān)部分如下:
<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">我通過相對(duì)路徑到相鄰的state</a></li> <li><a ui-sref="content.photos.detail">我通過絕對(duì)路徑到相鄰的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">通過相對(duì)路徑去子state</a> <div ui-view></div>
photos-detail-comment.html 則很簡單:
<h1>photos-detail-comment</h1>
app.js state多級(jí)嵌套的設(shè)置為
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
如果一個(gè)state,沒有通過鏈接找到它,那就可以把這個(gè)state設(shè)置為abstract:true,我們把以上的content和content.photos這2個(gè)state設(shè)置為抽象。
.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'}
}
})
那么,當(dāng)一個(gè)state設(shè)置為抽象,如果通過ui-sref或路由導(dǎo)航到該state會(huì)出現(xiàn)什么結(jié)果呢?
--會(huì)導(dǎo)航到默認(rèn)路由上
$urlRouterProvider.otherwise('home');
即
.state('content.home',{
url: 'home',
views:{
"body@content":{templateUrl: 'partials/home.html'}
}
})
最終把partials/home.html顯示出來。
使用控制器
在實(shí)際項(xiàng)目中,數(shù)據(jù)大多從controller中來。
首先在路由中設(shè)置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.現(xiàn)在的文件結(jié)構(gòu)為:
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(){
//調(diào)用父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間如何傳路由參數(shù)
在content.photos.detail這個(gè)state設(shè)置接收一個(gè)路由參數(shù)。
.state('content.photos.detail',{
url: '/detail/:id',
templateUrl: 'partials/photos-detail.html',
controller: 'PhotoDetailController',
controllerAs: 'ctrPhotoDetail'
})
photos-list.html 送出一個(gè)路由參數(shù)
<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})">把路由參數(shù)送出。
controller.js PhotoDetailController控制器通過$stateParams獲取路由參數(shù)
...
//別名: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中獲取數(shù)據(jù)。
<h1>photo-details</h1>
<a class="btn btn-default" ui-sref=".comment">通過相對(duì)路徑去子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間如何傳字符串參數(shù)
在路由中這樣設(shè)置:
.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(){
//調(diào)用父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不僅可以接收路由參數(shù),還可以接收查詢字符串參數(shù)。
photo-detail.html 需要把查詢字符串參數(shù)傳遞出去
<h1>photo-details</h1>
<a class="btn btn-default" ui-sref=".comment">通過相對(duì)路徑去子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間如何傳遞對(duì)象
通過data屬性,把一個(gè)對(duì)象賦值給它。
.state('content',{
url: '/',
abstract: true,
data:{
user: "user",
password: "1234"
},
views:{
"":{templateUrl: 'partials/content.html'},
"header@content":{templateUrl: 'partials/header.html'},
}
})
給header.html加上一個(gè)對(duì)應(yīng)的控制器,并提供注銷方法。
$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;
}
}
}
}
})
添加一個(gè)有關(guān)登錄頁的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文件,現(xiàn)在的文件結(jié)構(gòu)為:
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">通過相對(duì)路徑去子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這個(gè)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這個(gè)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這個(gè)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');
});
}
]);
添加一個(gè)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()
});
});
}
]);
添加一個(gè)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個(gè)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>
相關(guān)文章
AngularJS使用ng-app自動(dòng)加載bootstrap框架問題分析
這篇文章主要介紹了AngularJS使用ng-app自動(dòng)加載bootstrap框架問題,分析了前面文章中所述的ng-app自動(dòng)加載bootstrap出現(xiàn)的錯(cuò)誤原因與相應(yīng)的解決方法,需要的朋友可以參考下2017-01-01
深究AngularJS中ng-drag、ng-drop的用法
本篇文章主要介紹了深究AngularJS中ng-drag、ng-drop的用法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-06-06
Angular4學(xué)習(xí)之Angular CLI的安裝與使用教程
網(wǎng)上很多教程過時(shí),命令在angular4中不適用等等,所以下面這篇文章主要給大家介紹了關(guān)于Angular4學(xué)習(xí)之Angular CLI的安裝與使用教程的相關(guān)資料,需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2018-01-01
關(guān)于Angular2 + node接口調(diào)試的解決方案
這篇文章主要給大家介紹了關(guān)于Angular2 + node接口調(diào)試的解決方案,文中介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。2017-05-05
angularjs項(xiàng)目的頁面跳轉(zhuǎn)如何實(shí)現(xiàn)(5種方法)
本篇文章主要介紹了詳解angularjs項(xiàng)目的頁面跳轉(zhuǎn)如何實(shí)現(xiàn) ,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05
詳解在Angular項(xiàng)目中添加插件ng-bootstrap
這篇文章主要介紹了詳解在 Angular 項(xiàng)目中添加插件 ng-bootstrap,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07

