首先給你們介紹angular-ui-router的基本用法。css
如何引用依賴angular-ui-routerhtml
1
2
3
4
|
angular.module(
'app'
,[
"ui.router"
])
.config(
function
($stateProvider){
$stateProvider.state(stateName, stateCofig);
})
|
$stateProvider.state(stateName, stateConfig)node
stateName是string類型
stateConfig是object類型
//statConfig能夠爲空對象
$stateProvider.state("home",{});
//state能夠有子父級
$stateProvider.state("home",{});
$stateProvider.state("home.child",{})
//state能夠是鏈式的
$stateProvider.state("home",{}).state("about",{}).state("photos",{});jquery
stateConfig包含的字段:template, templateUrl, templateProvider, controller, controllerProvider, resolve, url, params, views, abstract, onEnter, onExit, reloadOnSearch, dataangularjs
$urlRouteProviderbootstrap
$urlRouteProvider.when(whenPath, toPath)
$urlRouterProvider.otherwise(path)
$urlRouteProvider.rule(handler)session
$state.goapp
$state.go(to, [,toParams],[,options])
形參to是string類型,必須,使用"^"或"."表示相對路徑;
形參toParams可空,類型是對象;
形參options可空,類型是對象,字段包括:location爲bool類型默認true,inherit爲bool類型默認true, relative爲對象默認$state.$current,notify爲bool類型默認爲true, reload爲bool類型默認爲falseide
$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.commentui
ui-sref
ui-sref='stateName'
ui-sref='stateName({param:value, param:value})'
ui-view
==沒有名稱的ui-view
1
2
3
4
|
<div ui-view></div>
$stateProvider.state(
"home"
,{
template:
"<h1>hi</h1>"
})
|
或者這樣配置:
1
2
3
4
5
6
7
|
$stateProvider.state(
"home"
{
views: {
""
: {
template:
"<h1>hi</h1>"
}
}
})
|
==有名稱的ui-view
1
2
3
4
5
6
7
8
|
<div ui-view=
"main"
></div>
$stateProvider.state(
"home"
,{
views: {
"main"
: {
template:
"<h1>hi</h1>"
}
}
})
|
==多個ui-view
1
2
3
4
5
6
7
8
|
<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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
<!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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<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,好比:
1
2
|
<div ui-view=
"header"
></div>
<div ui-view=
"body"
></div>
|
假設,以上頁面屬於一個名稱爲parent的state中。
咱們知道在ui-router中,一個state大體是這樣設置的:
1
2
|
<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和會根據頁頭上的點擊呈現不一樣的內容
1
2
|
<div ui-view=
"header"
></div>
<div ui-view=
"body"
></div>
|
header.html 把原先indext.html中nav部分放到這裏來
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<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 路由如今這樣設置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
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這個路由
1
2
3
4
5
6
|
.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>
1
2
3
4
5
6
7
|
.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>,來到:
1
2
3
4
5
6
|
.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>,來到:
1
2
3
4
5
6
|
.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中的相關部分以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<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
1
2
3
4
5
|
<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
1
2
3
|
<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多級嵌套的設置爲
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
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設置爲抽象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
.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');
即
1
2
3
4
5
6
|
.state(
'content.home'
,{
url:
'home'
,
views:{
"body@content"
:{templateUrl:
'partials/home.html'
}
}
})
|
最終把partials/home.html顯示出來。
使用控制器
在實際項目中,數據大多從controller中來。
首先在路由中設置state所用到的控制器以及控制器別名。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
<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設置接收一個路由參數。
1
2
3
4
5
6
|
.state(
'content.photos.detail'
,{
url:
'/detail/:id'
,
templateUrl:
'partials/photos-detail.html'
,
controller:
'PhotoDetailController'
,
controllerAs:
'ctrPhotoDetail'
})
|
photos-list.html 送出一個路由參數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
<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獲取路由參數
1
2
3
4
5
6
7
8
9
10
11
12
|
...
//別名: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中獲取數據。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<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間如何傳字符串參數
在路由中這樣設置:
1
2
3
4
5
6
|
.state(
'content.photos.detail.comment'
,{
url:
'/comment?skip&limit'
,
templateUrl:
'partials/photos-detail-comment.html'
,
controller:
'PhotoCommentController'
,
controllerAs:
'ctrPhotoComment'
})
|
controllers.js 中修改以下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
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 須要把查詢字符串參數傳遞出去
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<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屬性,把一個對象賦值給它。
1
2
3
4
5
6
7
8
9
10
11
12
|
.state(
'content'
,{
url:
'/'
,
abstract:
true
,
data:{
user:
"user"
,
password:
"1234"
},
views:{
""
:{templateUrl:
'partials/content.html'
},
"header@content"
:{templateUrl:
'partials/header.html'
},
}
})
|
給header.html加上一個對應的控制器,並提供註銷方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
$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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
.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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
<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 修改以下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
<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事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
.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中:
1
2
3
4
5
6
7
8
9
10
11
12
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<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 增長以下
1
2
3
4
5
6
7
8
9
10
11
|
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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
.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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
.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));
}
})
|
以上,添加了
1
2
3
|
data:{
required:
true
}
|
同理,content.photos.detail.comment這個state
1
2
3
4
5
6
7
8
9
|
.state(
'content.photos.detail.comment'
,{
url:
'/comment?skip&limit'
,
templateUrl:
'partials/photos-detail-comment.html'
,
controller:
'PhotoCommentController'
,
controllerAs:
'ctrPhotoComment'
,
data:{
required:
true
}
})
|
StateNotFound事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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:
1
2
3
4
5
6
|
.state(
'content.notfound'
,{
url:
'notfound'
,
views: {
"body@content"
: {templateUrl:
'partials/page-not-found.html'
}
}
})
|
page-not-found.html
1
2
3
|
<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事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
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
1
2
3
4
5
6
7
8
9
|
.state(
'content.log'
,{
url:
'log'
,
data:{
required:
true
},
views: {
"body@content"
: {templateUrl:
'partials/log.html'
}
}
})
|
log.html
1
2
3
4
5
6
7
8
|
<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事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
.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
1
2
3
|
<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>
|