原文:https://scotch.io/tutorials/angular-routing-using-ui-router
AngularJS提供了一种非常方便的单页应用程序。当创建单页应用程序时,路由将非常重要。我们希望我们的导航感觉像一个正常的网站,仍然没有我们的网站刷新。我们已经使用常规的ngRoute方法进行了angular 路由。
今天我们将使用UI-Router查看路由。
概述
1.什么是angularUI路由器
UI-Router是由AngularUI团队构建的AngularJS的路由框架。它提供了与ngRoute不同的方法,因为它会根据应用程序的状态(state)更改应用程序视图,而不仅仅是路由URL。
2.states与url路由
使用这种方法,您的视图(view)和路由(route)不会被绑定到网站URL。这样,即使URL没有更改,也可以使用路由更改网站的部分。
在使用ngRoute时,您必须使用ngInclude或其他方法,这可能会让人感到困惑。现在,您的所有状态(states)、路由(routing)和视图(views)都在您的. config()中处理,这将在使用您的应用程序的自顶向下视图时提供帮助。
样例应用程序
让我们做一些类似于我们所做的其他路由教程。让我们创建一个home页和一个about页。
开始
让我们开始我们的应用程序,首先需要一些文件
file | 注释 |
---|---|
index.html | angularJs主页面 |
home.html | home页单页面 |
about.html | about页单页面 |
module.js | angular代码 |
homeList.html | home页的子页面 |
homePara.html | home页的子页面 |
index.html(code)
<!DOCTYPE html>
<!--将angular应用程序通过ng-app注入进来-->
<html lang="en" ng-app="app">
<head>
<meta charset="UTF-8">
<title>ui-router</title>
<link rel="stylesheet" href="css/bootstrap.css">
<script src="js/angular.js"></script>
<!--注意:先引入angular.js,再引入angular-ui-router.js-->
<script src="js/angular-ui-router.js"></script>
<!--最后引入自定义的js文件-->
<script src="js/module.js"></script>
</head>
<body>
<nav class="navbar navbar-inverse">
<ul class="nav navbar-nav">
<li><a ui-sref="home">Home</a></li>
<li><a ui-sref="about">About</a></li>
</ul>
</nav>
<div class="container">
<div ui-view></div>
</div>
</body>
</html>
注意:
ui-router除了加载Angular之外,我们还加载了它。ui-rouer与Angular核心分开,就像ngRoute是分开的。(先加载angular.js再加载angular-ui-router.js)
当使用UI-Router创建链接时,您将使用ui-sref。href将从此生成,您希望将其指向应用程序的某个状态。这些都是在你的app.js。
- 我们也使用
<div ui-view></div>
而不是ngRoute的<div ng-view></div>。
我们现在开始我们的Angular应用程序app.js。
app.js(code)
//module.js(尽量不要创建全局变量,污染全局环境)
//将“ui.router”模块依赖注入到主模块中
angular.module("app", ["ui.router"]).
config(["$stateProvider", "$urlRouterProvider", function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/home");
$stateProvider.
state("home", {
url: "/home",
templateUrl: "tpl/home.html",
}).
state("about", {
url: "/about",
templateUrl: "tpl/about.html",
})
}])
注意:
- 现在我们已经创建了app的模块,我们已经应用到我们的index.html文件。
- 在这里我们有一个.state()home和about。在home状态下,我们正在使用模板文件home.html。
- 我们填写我们的home.html网页,以便我们可以看到信息。
home.html(code)
<div class="jumbotron text-center">
<h1>The Homey Page</h1>
<p>This page demonstrates <span class="text-danger">nested</span> views.</p>
</div>
about.html(code)
<div class="alert alert-danger">
about page
</div>
……实现图
嵌套视图 home page
<!--home.html-->
<div class="jumbotron text-center">
<h1>The Homey Page</h1>
<p>This page demonstrates <span class="text-danger">nested</span> views.</p>
<!--嵌套路由-->
<a ui-sref=".list" class="btn btn-danger">list子页面</a>
<a ui-sref=".para" class="btn btn-danger">para子页面</a>
<div ui-view></div>
</div>
注意:
- 当链接到嵌套视图时,我们将使用点标记:ui-sref=”.list”和ui-sref=”.para”。
这些将在我们的angular中定义,一旦我们设置在那里,我们将注入到我们的新的
<div ui-view></div>
。在我们的module.js文件中,我们创建这些嵌套状态。
//module.js(尽量不要创建全局变量,污染全局环境)
//将“ui.router”模块依赖注入到主模块中
angular.module("app", ["ui.router"]).config(["$stateProvider", "$urlRouterProvider", function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/home");
$stateProvider.state("home", {
url: "/home",
templateUrl: "tpl/home.html",
}).state("home.list", {
url: '/list',
templateUrl: 'tpl/homeList.html',
controller: function ($scope) {
$scope.dogs = ["阿狗", "阿猫", "啊呆"]
}
}).state("home.para", {
url: "/para",
templateUrl: "tpl/homePara.html",
}).state("about", {
url: "/about",
templateUrl: "tpl/about.html",
})
}]);
现在我们定义的 home.html与实际状态相关联。随着home.list和home.para创建,这些链接现在将提供模板并注入ui-view。
最后我们需要做的是为home.html定义homeList.html文件。我们也在一个控制器中传递了我们将在模板文件中使用的狗列表。
<!--homeList.html-->
<div>
<ul>
<li ng-repeat="dog in dogs">
dog
</li>
</ul>
</div>
…实现图
绝对路由
如果你使用绝对 url 匹配的方式,那么你需要给你的url字符串加上特殊符号”^”。
$stateProvider
.state('contacts', {
url: '/contacts',
...
})
.state('contacts.list', {
url: '^/list',
...
});
路由将成为:
‘contacts’状态将匹配”/contacts”
‘contacts.list’状态将匹配”/list”。子状态的url没有附在父状态的url之后的,因为使用了^。
多视图 about page
在应用程序中有多个视图是非常强大的。也许你在你的网站上有一个侧边栏,上面有流行的帖子,最近的帖子,用户,等等。这些都可以被分离出来并注入到我们的模板中。每个人都有自己的控制器和模板文件,这样我们的应用程序就会保持干净。
让我们的应用程序模块化,也可以让我们在不同的模板中重用数据。
对于我们的About页面,让我们创建两个列,并且每个列都有它自己的数据。我们将首先处理视图(about.html),然后看看如何使用ui - router进行此操作。
<!--about.html-->
<div class="alert alert-danger">
about page
</div>
<div class="row">
<div class="col-md-6">
<div ui-view="one"></div>
</div>
<div class="col-md-6">
<div ui-view="two"></div>
</div>
</div>
这里有多个视图。一个叫one,另一个是two。
为什么有人会使用这种方法呢?这是一个很好的问题。我们是否在创建一个过于模块化的应用程序,这可能会让人感到困惑?从官方的ui - router文档中,这里有一个很好的例子,说明为什么会有多个命名视图。在他们的例子中,他们展示了应用程序的不同部分。每个部分都有它自己的数据,所以每个部分都有自己的控制器(controller)和模板文件(template),使得构建类似这样的东西很容易。
现在,我们的视图已经创建好了,让我们来看看如何将模板文件和控制器应用到每个视图。我们回到我们的module . js。
//module.js(尽量不要创建全局变量,污染全局环境)
//将“ui.router”模块依赖注入到主模块中
angular.module("app", ["ui.router"]).config(["$stateProvider", "$urlRouterProvider", function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/home");
$stateProvider.state("home", {
url: "/home",
templateUrl: "tpl/home.html",
}).state("home.list", {
url: '/list',
templateUrl: 'tpl/homeList.html',
controller: function ($scope) {
$scope.dogs = ["阿狗", "阿猫", "啊呆"]
}
}).state("home.para", {
url: "/para",
templateUrl: "tpl/homePara.html",
}).state("about", {
url: "/about",
views: {
"": {templateUrl: 'tpl/about.html'},
'one@about': {template: 'i am a column'},
'two@about': {
templateUrl: 'tpl/aboutList.html',
controller: 'controller1'
}
}
});
}]).controller("controller1",["$scope",function($scope){
$scope.scotches = [
{
name: 'Macallan 12',
price: 50
},
{
name: 'Chivas Regal Royal Salute',
price: 10000
},
{
name: 'Glenfiddich 1937',
price: 20000
}
];
}]);
<table class="table">
<tr>
<td>name</td>
<td>cost</td>
</tr>
<tr ng-repeat="item in scotches">
<td>{{item.name}}</td>
<td>{{item.price}}</td>
</tr>
</table>
ui -路由器将每个视图分配给一个绝对名称。它的结构是viewName@stateName。由于我们的主要的ui视图在我们的状态,我们给它一个空白的名字。另外两个视图,因为One@about和two @ about。
以这种方式命名方案让我们在一个状态下定义多个视图。这些文档很好地解释了这个概念,我鼓励大家看看他们的例子。非常强大的工具。
..实现图
url参数
首先先对$stateParams服务
之前看到的$stateParams
服务是一个对象,包含 url 中每个参数的键/值。$stateParams可以为控制器或者服务提供 url 的各个部分。
注意:$stateParams
服务必须与一个控制器(controller)相关,并且$stateParams中的“键/值”也必须事先在那个控制器的url属性中有定义。
使用$stateParams的两个陷阱
- 只有当状态被激活并且状态的所有依赖项都被注入时,
$stateParams
对象才存在。这代表你不能再状态的resolve函数中使用$stateParams
对象,可以使用$state.current.params
来代替。
$stateProvider.state('contacts.detail', {
resolve: {
someResolve: function($state){
//*** 不能在这里使用 $stateParams , the service is not ready ***//
//*** 使用 $state.current.params 来代替 ***//
return $state.current.params.contactId + "!"
};
},
// ...
})
- 在状态控制器中,$stateParams对象只包含那些在状态中定义的参数,因此你不能访问在其他状态或者祖先状态中定义的参数。
$stateProvider.state('contacts.detail', {
url: '/contacts/:contactId',
controller: function($stateParams){
$stateParams.contactId //*** Exists! ***//
}
}).state('contacts.detail.subitem', {
url: '/item/:itemId',
controller: function($stateParams){
$stateParams.contactId //*** 注意! DOESN'T EXIST!! ***//
$stateParams.itemId //*** Exists! ***//
}
})
// 如果状态中 url 属性是:
url: '/users/:id/details/{type}/{repeat:[0-9]+}?from&to'
// 当浏览
'/users/123/details//0'
// $stateParams 对象将是
{ id:'123', type:'', repeat:'0' }
// 当浏览
'/users/123/details/default/0?from=there&to=here'
// $stateParams 对象将是
{ id:'123', type:'default', repeat:'0', from:'there', to:'here' }
1.基本参数(:value)
$stateProvider.
$state("contacts.detail",{
//这里设置url参数
url:'/contacts/:contactId',
templateUrl:'contacts.detail.html',
controller:function($stateParams){
//获取参数传来的值
id = $stateparams.contactId;
}
})
特例:含正则表达式的参数
2.查询参数(?value)
可以指定?来制定参数作为查询参数
url:'/contacts?myParams&add'
//匹配'/contacts?myParams=value&add=value2'
1)
2)使用参数而不用在状态url中指定它们
即使参数没有出现在url中,您仍然可以指定要接收的参数。您需要在状态中添加一个新的字段params,并根据链接中使用参数指定的链接创建链接
例如,你有状态。
$urlRouterProvider
$urlRouterProvider
负责处理在状态配置中指定的url路由方式之外的 url 请求的路由方式。
$urlRouterProvider
负责监视$location
,当$location
改变后,$urlRouterProvider
将从一个列表,一个接一个查找匹配项,直到找到。所有 url 都编译成一个UrlMatcher对象。
$urlRouterProvider
有一些实用的方法,可以在module.config中直接使用。
when() for redirection 重定向
参数:
what - String | RegExp | UrlMatcher,你想重定向的传入路径
handler - String | Function 将要重定向到的路径1)handler 作为 String(如果handler是字符串,它被视为一个重定向,并且根据匹配语法决定重定向的地址。)
2)handler 作为 Function
如果handler是一个函数,这个函数是注入一些服务的。如果$location
匹配成功,函数将被调用。你可以选择性注入$match
。
falsy
表明规则不匹配,$urlRouter
将试图寻找另一个匹配
String 该字符串作为重定向地址并且作为参数传递给$location.url()
nothing或者任何为真的值,告诉$urlRoute
rurl 已经被处理
1)
app.config(function($urlRouterProvider){
// when there is an empty route, redirect to /index
$urlRouterProvider.when('', '/index');
// You can also use regex for the match parameter
$urlRouterProvider.when('/aspx/i', '/index');
})
-
2)handler 作为 Function
如果handler是一个函数,这个函数是注入一些服务的。如果
location匹配成功,函数将被调用。你可以选择性注入
match。
函数可以返回:
falsy - 表明规则不匹配,
urlRouter将试图寻找另一个匹配String−该字符串作为重定向地址并且作为参数传递给
location.url()
nothing或者任何为真的值,告诉$urlRouterurl 已经被处理
结论
这是一个关于ui -路由器的伟大工具的概述。您可以使用它来做的事情是不可思议的,当您将应用程序看作状态而不是ngRoute选项时,可以轻松地创建具有模块化和可扩展的角应用程序。
相关ui-router:http://ngmodules.org/modules/ui-router#get-started