Pertama sekali, saya akan memperkenalkan anda kepada penggunaan asas angular-ui-router.
Cara merujuk kebergantungan angular-ui-router
angular.module('app',["ui.router"]) .config(function($stateProvider){ $stateProvider.state(stateName, stateCofig); })
$stateProvider.state(stateName, stateConfig)
stateName ialah daripada jenis rentetan
stateConfig ialah jenis objek
//statConfig boleh menjadi objek kosong
$stateProvider.state("home",{});
//negeri boleh mempunyai anak dan ibu bapa
$stateProvider.state("home",{});
$stateProvider.state("home.child",{})
//keadaan boleh dirantai
$stateProvider.state("home",{}).state("about",{}).state("photos",{});
StateConfig mengandungi medan: template, templateUrl, templateProvider, controller, controllerProvider, resolve, url, params, views, abstract, onEnter, onExit, reloadOnSearch, data
$urlRouteProvider
$urlRouteProvider.when(whenPath, toPath)
$urlRouterProvider.otherwise(path)
$urlRouteProvider.rule(pengendali)
$state.go
$state.go(to, [,toParams],[,options])
Parameter formal untuk adalah jenis rentetan, yang diperlukan Gunakan "^" atau "."
Parameter formal toParams boleh dibatalkan dan jenisnya ialah objek;
Pilihan parameter formal boleh menjadi batal, dan jenisnya ialah objek Medan termasuk: lokasi ialah jenis bool dan lalai adalah benar, warisan ialah jenis bool dan lalai adalah benar, relatif ialah objek dan lalai ialah $. state.$current, notify ialah jenis bool dan lalainya adalah benar, dan muat semula ialah jenis bool dan lalainya adalah benar
$state.go('photos.detail')
$state.go('^.list') ke keadaan bersebelahan, seperti dari photo.detail ke photo.list
$state.go('^.detail.comment') ke negeri cucu, seperti dari photo.detail ke photo.detial.comment
ui-sref ui-sref='stateName'
ui-sref='stateName({param:value, param:value})'
ui-view == ui-view tanpa nama
<div ui-view></div> $stateProvider.state("home",{ template: "<h1>hi</h1>" })
$stateProvider.state("home"{ views: { "": { template: "<h1>hi</h1>" } } })
<div ui-view="main"></div> $stateProvider.state("home",{ views: { "main" : { template: "<h1>hi</h1>" } } })
<div ui-view></div> <div ui-view="data"></div> $stateProvider.state("home",{ views: { "":{template: "<h1>hi</h1>"}, "data": {template: "<div>data</div>"} } })
Struktur fail projek modul_nod/
separa/
.....tentang.html
.....home.html
.....photos.html
app.js
index.html
Buat keadaan dan paparan
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' }) })
<!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>
Lompat antara negeri
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>
Pandangan berbilang dan keadaan bersarang Kadangkala, mungkin terdapat berbilang paparan-ui pada halaman, seperti:
<div ui-view="header"></div> <div ui-view="body"></div>
Kami tahu bahawa dalam ui-router, keadaan ditetapkan secara kasar seperti ini:
<div ui-view="header"></div> <div ui-view="body"></div>
Klik pada pautan halaman yang sepadan dengan pengepala, yang mungkin melompat ke sub-halaman lain yang muncul pada kedudukan
. Pada masa ini, hubungan anak-ibu bapa muncul pada halaman dan setiap halaman tergolong dalam keadaan tertentu, jadi hubungan anak-ibu bapa muncul antara negeri. Subhalaman yang diubah hala ini boleh dipanggil parent.son1, parent.son2... dalam tetapan penghalaan Ini ialah sarang keadaan.Tambah content.html dan header.html pada struktur fail sedia ada dan struktur fail menjadi:
modul_nod/
separa/
.....tentang.html
.....home.html
.....photos.html
.....kandungan.html
.....header.html
app.js
index.html
content.html mengandungi berbilang paparan-ui Satu paparan-ui berkaitan dengan pengepala halaman dan tetap tidak berubah; paparan-ui akan memaparkan kandungan yang berbeza mengikut klik pada pengepala halaman
<div ui-view="header"></div> <div ui-view="body"></div>
<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>
penghalaan app.js kini disediakan seperti ini
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'} } }) })
→ Pergi ke laluan rumah
以上,告诉我们partials/home.html将会被加载到与"body@content"匹配的ui-view中。暂时对应的ui-view还没有出现,于是等待。
→ 路由看到index.html上的
.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页面上的各个部分
看到
,就加载如下:"header@content":{templateUrl: 'partials/header.html'},
看到
,先加载 "body@content":{templateUrl: 'partials/home.html'}→ 点击header上的链接
点击Photos,来到:
.state('content.photos',{ url: 'photos', views:{ "body@content":{templateUrl: 'partials/photos.html'} } })
把partials/photos.html显示到
中去。点击
,来到:.state('content.about',{ url:'about', views:{ "body@content":{templateUrl: 'partials/about.html'} } })
把partials/about.html显示到
中去。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
如何到达这个子页面呢?修改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>
以上,通过Photos来到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 则很简单:
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>
以上,通过把路由参数送出。
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>