时光的涂鸦墙

code is poetry

angularJs之路由

为什么需要前端路由

  • Ajax请求不会留下history记录
  • 用户无法直接通过 url 进入应用中的指定页面(保存书签,链接分享给朋友)
  • AjaxSEO不友好(没法让搜索引擎索引)

Angular 路由

APP中定义多个页面的控制器,并给出对应的模板。然后$routeProvider进行配置,即可将 URL 映射到这些控制器和视图。 首先定义一个基本的 Angular APP,并引入ngRoute

Angular$routeServicengRoute模块里。需要引入它对应的 JavaScript 文件,并在我们的 APP 里ngRoute添加为模块依赖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var app = angular
.module('ngRouteExample', ['ngRoute'])
.controller('MainController', function($scope) {})
.config(function($routeProvider, $locationProvider) {
$routeProvider
.when('/users', {
templateUrl: 'user-list.html',
controller: 'UserListCtrl'
})
.when('/users/:username', {
templateUrl: 'user.html',
controller: 'UserCtrl'
})
.otherwise({
redirectTo: '/hello'
})

// configure html5
$locationProvider.html5Mode(true)
})

上述代码中,$routeProvider定义了两个 URL 的映射:/users使用user-list.html作为模板,UserListCtrl作为控制器;/users/:username则会匹配类似/users/alice之类的 URL,稍后你会看到如何获得:username匹配到的值。先看首页的模板:

HTML5Mode: 服务器端路由和客户端路由的 URL 以#分隔。例如/foo/bar#/users/alice,Angular 通过操作锚点来进行路由。 然而html5Mode(true)将会去除#,URL 变成/foo/bar/users/alice(这需要浏览器支持 HTML5 的,因为此时 Angular 通过pushState来进行路由)。 此时服务器对所有的客户端路由的 URL 都需要返回首页(/foo/bar)视图,再交给 Angular 路由到/foo/bar/users/alice对应的视图。

1
2
3
4
5
<div ng-controller="MainController">
Choose: <a href="users">user list</a> | <a href="users/alice">user: alice</a>

<div ng-view></div>
</div>

注意到模板文件中有一个div[ng-view],子页面将会载入到这里。

路由参数

用户列表页面:

1
app.controller('UserListCtrl', function($scope) {})
1
2
<!--user-list.html-->
<h1>User List Page</h1>

用户页面:

1
2
3
app.controller('UserCtrl', function($scope, $routeParams) {
$scope.params = $routeParams
})
1
2
3
<!--user.html-->
<h1>User Page</h1>
<span ng-bind="params.userName"></span>

我们点击首页的/users/alice时,将会载入user.htmlspan的值为alice$routeParams提供了当前的路由参数,例如:

1
2
3
4
5
6
// Given:
// URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
// Route: /Chapter/:chapterId/Section/:sectionId
//
// Then
$routeParams ==> {chapterId:'1', sectionId:'2', search:'moby'}

UI-Router

UI-Router 是 Angular-UI 提供的客户端路由框架,它解决了原生的 ng-route 的很多不足:

  • 视图不能嵌套。这意味着$scope会发生不必要的重新载入。这也是我们在Onboard 中引入 ui-route 的原因。
  • 同一 URL 下不支持多个视图。这一需求也是常见的:我们希望导航栏用一个视图(和相应的控制器)、内容部分用另一个视图(和相应的控制器)。

UI-Router 提出了$state的概念。一个$state是一个当前导航和 UI 的状态,每个$state需要绑定一个 URL Pattern。 在控制器和模板中,通过改变$state来进行 URL 的跳转和路由。这是一个简单的例子:

1
2
3
4
<!-- in index.html -->
<body ng-controller="MainCtrl">
<section ui-view></section>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// in app-states.js
var myUIRoute = angular.module('MyUIRoute', ['ui.router', 'ngAnimate'])
myUIRoute.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/contacts')
$stateProvider
.state('contacts', {
url: '/contacts',
template: 'contacts.html',
controller: 'ContactCtrl'
})
.state('contacts.detail', {
url: '/contacts/:contactId',
templateUrl: 'contacts.detail.html',
controller: function($stateParams) {
// If we got here from a url of /contacts/42
$stateParams.contactId === '42'
}
})
})

当访问/contacts时,contacts $state被激活,载入对应的控制器和视图。在 ui-router 时,通常使用$state来完成页面跳转, 而不是直接操作 URL。例如,在脚本使用$state.go

1
2
$state.go('contacts') // 指定state名,相当于跳转到 /contacts
$state.go('contacts.detail', { contactId: 42 }) // 相当于跳转到 /contacts/42

在模板中使用ui-sref(这是一个 Directive):

1
2
<a ui-sref="contacts">Contacts</a>
<a ui-sref="contacts.detail({contactId: 42})">Contact 42</a>

嵌套视图

不同于 Angular 原生的ng-route,ui-router 的视图可以嵌套,视图嵌套通常对应着$state的嵌套。 contacts.detailcontacts的子$statecontacts.detail.html也将作为contacts.html的子页面:

1
2
3
<!-- contacts.html -->
<h1>My Contacts</h1>
<div ui-view></div>
1
2
<!-- contacts.detail.html -->
<span ng-bind="contactId"></span>

上述ui-view的用法和ng-view看起来很相似,但不同的是ui-view可以配合$state进行任意层级的嵌套, 即contacts.detail.html中仍然可以包含一个ui-view,它的$state可能是contacts.detail.hobbies

命名视图

在 ui-router 中,一个$state下可以有多个视图,它们有各自的模板和控制器。这一点也是ng-route所没有的, 给了前端路由极大的灵活性。来看例子:

1
2
3
4
5
6
<!-- index.html -->
<body>
<div ui-view="filters"></div>
<div ui-view="tabledata"></div>
<div ui-view="graph"></div>
</body>

这一个模板包含了三个命名的ui-view,可以给它们分别设置模板和控制器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$stateProvider
.state('report',{
views: {
'filters': {
templateUrl: 'report-filters.html',
controller: function($scope){ ... controller stuff just for filters view ... }
},
'tabledata': {
templateUrl: 'report-table.html',
controller: function($scope){ ... controller stuff just for tabledata view ... }
},
'graph': {
templateUrl: 'report-graph.html',
controller: function($scope){ ... controller stuff just for graph view ... }
}
}
})

综合实例

HTML:

1
2
//uiRoute.html
<div ui-view></div>
1
2
3
4
5
6
7
//index.html
<div class="container">
//头部
<div ui-view="topbar"></div>
//主体
<div ui-view="main"></div>
</div>
1
2
3
4
5
6
7
8
9
10
//topbar.html //顶部
<nav class="navbar navbar-inverse" role="navigation">
<div class="navbar-header">
<a class="navbar-brand" ui-sref="#">ui-router综合实例</a>
</div>
<ul class="nav navbar-nav">
<li><a ui-sref="index">首页</a></li>
<li><a ui-sref="index.usermng">用户管理</a></li>
</ul>
</nav>
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
//usermng.html //左侧
<div class="row">
<div class="col-md-3">
<div class="row">
<div class="col-md-12">
<div class="list-group">
<a ui-sref="#" class="list-group-item active">用户分类</a>
<a ui-sref="index.usermng.highendusers" class="list-group-item"
>高端用户</a
>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<button class="btn btn-primary" ng-click="addUserType()">
新增用户
</button>
</div>
</div>
</div>
<div class="col-md-9">
//用于存放右边部分
<div ui-view></div>
</div>
</div>
1
//highendusers.html 。。。

javascript:

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
var routerApp = angular.module('routerApp', ['ui.router'])
routerApp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/index')
$stateProvider
.state('index', {
url: '/index',
views: {
'': {
templateUrl: 'tpls/index.html'
},
'topbar@index': {
templateUrl: 'tpls/topbar.html'
},
'main@index': {
templateUrl: 'tpls/home.html'
}
}
})
.state('index.usermng', {
url: '/usermng',
views: {
'main@index': {
templateUrl: 'tpls/usermng.html',
controller: function($scope, $state) {
$scope.addUserType = function() {
$state.go('index.usermng.addusertype')
}
}
}
}
})
.state('index.usermng.highendusers', {
url: '/highendusers',
templateUrl: 'tpls/highendusers.html'
})
.state('index.usermng.addusertype', {
url: '/addusertype',
templateUrl: 'tpls3/addusertypeform.html',
controller: function($scope, $state) {
$scope.backToPrevious = function() {
window.history.back()
}
}
})
})

转载自:http://harttle.com/2015/06/10/angular-route.html

© 2019 elaine