带参数的 AngularJS 路由
⚡ 智能摘要
AngularJS 中的路由通过映射将单个 HTML 页面转换为多视图应用程序。ping URL 片段到模板和控制器。ngRoute 模块和 $routeProvider 服务定义了这些映射。pings,而 ng-view 指令则注入匹配的模板。

在深入了解 AngularJS 的路由机制之前,首先需要了解路由机制最初是为哪种类型的应用程序设计的。以下部分将介绍这一背景,后续的每项技术都将以此为基础展开。
什么是单页应用程序?
单页应用程序(SPA)是一种Web应用程序,它只加载一个HTML页面,然后根据用户交互动态更新该页面。SPA不会像传统Web应用程序那样每次点击都从服务器请求新的文档,而是只更新页面中发生变化的部分。
这种设计会带来一个问题。如果浏览器始终不跳转到新文档,地址栏就不会改变,用户也就无法收藏、分享或使用后退按钮。路由机制正是为了解决这个问题而设计的。
AngularJS 中的路由是什么?
AngularJS 中的路由 是一种允许您创建单页应用程序的方法。它使您能够创建不同的应用程序。 URLAngularJS 路由用于 Web 应用程序中不同的内容。它还有助于根据选择的路由显示多个内容。这在 [此处应填写具体说明] 中指定。 URL 在#符号之后。
我们以一个托管在……上的网站为例。 URL http://example.com/index.html.
此页面是应用程序的主屏幕。假设应用程序组织了一个活动,用户想要列出活动、查看某个活动的详细信息或删除某个活动。在启用了路由的单页应用程序中,所有这些功能都可以通过以下链接访问。
# 符号将与不同的路线(ShowEvent、DisplayEvent 和 DeleteEvent)一起使用。
- 要查看所有事件,用户将被引导至 http://example.com/index.html#ShowEvent
- 要观看某个特定活动,他们会被引导至 http://example.com/index.html#DisplayEvent
- 要删除事件,他们会被引导至 http://example.com/index.html#DeleteEvent
请注意主要 URL 其余部分保持不变。只有 # 后面的片段会改变,AngularJS 会监听这个片段。理解了这个概念之后,下一节将介绍在一切正常运行之前必须连接的各个组件。
使用 $routeProvider 添加 AngularJS 路由
如前所述,路线 AngularJS 用于将用户路由到应用程序的不同视图。此路由在同一个 HTML 页面上完成,因此用户感觉他们没有离开当前页面。
为了实现路由,您的应用程序必须按任意顺序执行以下主要步骤。
- 参考 angular-route.js。这 JavaScript 文件,由……开发 Google包含所有路由功能,必须包含该模块,以便应用程序可以引用所需的路由模块。
- 在您的应用程序中添加对 ngRoute 模块的依赖。如果没有此依赖,AngularJS 应用程序将无法使用路由功能。
以下是该语句的一般语法。这只是包含 ngRoute 关键字的模块的普通声明。
var module = angular.module("sampleApp", ['ngRoute']);
- 配置您的 $routeProvider。这将为您的应用程序提供各种路由,其语法很简单:当选择相关路径时,使用该路由显示指定的视图。
when(path, route)
- 从 HTML 页面内链接到您的路线。在您的 HTML 页面中,您将添加指向应用程序中各种可用路线的参考链接。
<a href="#!/route1">Route 1</a><br/>
- 最后将包括 ng-view 指令,通常位于 div 标签中。这将用于在选择相关路线时注入视图的内容。
👍 提示: 这五个步骤都是必需的。缺少 angular-route.js 引用是路由静默无声地不执行任何操作的最常见原因,因为如果没有它,$routeProvider 就不会存在。下一节将通过一个可运行的示例来展示这五个步骤。
AngularJS 路由示例
现在,让我们看一个使用上述步骤进行路由的示例。
在我们带有参数的 AngularJS 路由示例中,
- 其中一个链接是显示主题 AngularJS 当然,另一个是 Node.js 课程。
- 当用户点击任一链接时,将显示该课程的主题。
步骤1) 将 angular-route 文件作为脚本引用包含在内。
要使用多路由和多视图功能,必须创建此路由文件。您可以从 AngularJS 官网下载此文件。
步骤2) 添加 href 标签,代表指向“Angular JS 主题”和“Node JS 主题”的链接。
步骤3) 添加一个带有 ng-view 指令的 div 标签来表示视图。
这样,每当用户点击“Angular JS 主题”或“Node JS 主题”时,就会注入相应的视图。
步骤4) 在 AngularJS 的脚本标签中,添加“ngRoute 模块”和“$routeProvider”服务。
Code 说明:
- 引入“ngRoute模块”。有了它,Angular就能自动处理路由并理解所有路由命令。
- $routeProvider 是一个后台监听路由调用的服务。当用户点击链接时,它会检测到这一操作并决定采用哪条路由。
- 为 Angular 链接创建一个路由:当点击该链接时,注入 Angular.html 并使用 'AngularController' 来实现业务逻辑。
- 为 Node 链接创建一个路由,该路由注入 Node.html 并以相同的方式使用 'NodeController'。
步骤5) 接下来是添加控制器来处理 AngularController 和 NodeController 的业务逻辑。
在每个控制器中,我们创建一个键值对数组,用于存储每门课程的主题名称和描述。数组变量“tutorial”被添加到每个控制器的作用域对象中。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Event Registration</title> </head> <body ng-app="sampleApp"> <script src="https://code.angularjs.org/1.8.3/angular.min.js"></script> <script src="https://code.angularjs.org/1.8.3/angular-route.js"></script> <h1> Guru99 Global Event</h1> <div class="container"> <ul> <li><a href="#!/Angular">Angular JS Topics</a></li> <li><a href="#!/Node">Node JS Topics</a></li> </ul> <div ng-view></div> </div> <script> var sampleApp = angular.module('sampleApp', ['ngRoute']); sampleApp.config(['$routeProvider', function($routeProvider) { $routeProvider. when('/Angular', { templateUrl: 'Angular.html', controller: 'AngularController' }). when('/Node', { templateUrl: 'Node.html', controller: 'NodeController' }); }]); sampleApp.controller('AngularController', function($scope) { $scope.tutorial = [ {Name: "Controllers", Description: "Controllers in action"}, {Name: "Models", Description: "Models and binding data"}, {Name: "Directives", Description: "Flexibility of Directives"} ]; }); // NodeController follows the same shape with Node.js topics sampleApp.controller('NodeController', function($scope) { $scope.tutorial = [{Name: "Promises", Description: "Power of Promises"}]; }); </script> </body> </html>
⚠️ 已进行更正。 此 <title> 标签位于内部 <body>, chrset="UTF 8" 拼写错误,第二个链接指向 #Node.html 而不是注册路线 /Node模板路径带有前导斜杠,该斜杠会解析为域根目录。
步骤6) 创建名为 Angular.html 和 Node.html 的页面。对于每个页面,我们执行以下步骤。
这些步骤将确保数组的所有键值对都显示在每个页面上。
- 使用 ng-repeat 指令 遍历教程变量中定义的每个键值对。
- 显示每个键值对的名称和描述。
- Angular.html
<h2>Angular</h2> <ul ng-repeat="ptutor in tutorial"> <li>Course : {{ptutor.Name}} - {{ptutor.Description}}</li> </ul>
- 节点.html — 与上面的列表完全相同,只是标题改为了“节点”。两个模板的内容相同。
tutorial每个控制器都从其自身的作用域提供该变量。
⚠️ 更正: 原 Angular.html 文件中的标题为“Anguler”。上面已更正拼写错误。
如果代码执行成功,在浏览器中运行代码时将显示以下输出。
输出:
如果您点击 AngularJS 主题链接,将显示以下输出。
输出清楚地表明,
- 当点击“Angular JS 主题”链接时,我们在代码中声明的 routeProvider 会决定应注入 Angular.html 代码。
- 此代码将被注入到包含 ng-view 指令的“div”标签中。此外,课程描述的内容来自“tutorial 变量”,它是 AngularController 中定义的范围对象的一部分。
- 当点击 Node.js 主题,将会发生相同的结果,并会体现出 Node.js 主题的视图。
- 另外,请注意该页面 URL 保持不变。只有 # 标签后面的路由会改变,这就是单页应用程序的概念。# 标签中的 #hash 标签 URL 是路由(在本例中为“Angular”)和主 HTML 页面(Sample.html)之间的分隔符。
此示例仅在用户点击与已注册路由匹配的链接时有效。下一节将处理没有任何匹配项时应发生的情况。
在 AngularJS 中创建默认路由
AngularJS 中的路由还提供了默认路由的功能。如果现有路由不匹配,则会选择此路由。
通过在定义 $routeProvider 服务时添加以下条件来创建默认路由。
以下语法的意思很简单,就是如果现有路由都不匹配,则重定向到另一个页面。
otherwise({
redirectTo: 'page'
});
让我们使用上面相同的示例,并向我们的 $routeProvider 服务添加默认路由。
sampleApp.config(['$routeProvider', function($routeProvider) { $routeProvider. when('/Angular', { templateUrl: 'Angular.html', controller: 'AngularController' }). when('/Node', { templateUrl: 'Node.html', controller: 'NodeController' }). otherwise({ redirectTo: '/Angular' }); }]);
Code 说明:
- 这里我们使用的代码与上面相同,唯一的区别在于我们使用了 otherwise 语句和“redirectTo”选项来指定如果没有指定路由时应该加载哪个视图。在本例中,我们希望显示“/Angular”视图。
如果代码执行成功,在浏览器中运行代码时将显示以下输出。
输出:
从输出来看,
- 您可以清楚地看到,显示的默认视图是 AngularJS 视图。
- 这是因为当页面加载时,它会转到 $routeProvider 函数中的“otherwise”选项并加载“/Angular”视图。
默认路由决定加载哪个视图。下一节将介绍如何通过携带一个值,使单个路由能够服务于多个记录。 URL.
如何从 AngularJS 路由访问参数
Angular 还提供了在路由过程中传递参数的功能。这些参数会添加到路由的末尾。 URL例如, http://guru99/index.html#/Angular/1在这个 Angular 路由示例中,
- http://guru99/index.html 是我们的主要应用程序 URL
- # 符号是主应用程序之间的分隔符。 URL 以及路线
- Angular 是我们的路线
- 最后,'1' 是添加到我们的路线的参数
一般语法是 HTMLPage#/route/参数因此,较早的主题变为 Sample.html#/Angular/1、#/Angular/2 和 #/Angular/3,其中数字是主题 ID。
让我们详细了解一下如何实现带有参数的 Angular 路由。
步骤 1)将以下代码添加到您的视图中
- 添加一个表格,向用户显示 Angular JS 课程的所有主题。
- 添加一个表格行,用于显示“控制器”主题。对于此行,将 href 设置为“#!/Angular/1”,这样点击该主题时,参数 1 就会传递到页面中。 URL 沿着路线。
- 添加一行“模型”主题,并将 href 设置为“#!/Angular/2”,以便参数 2 在页面中传递。 URL.
- 添加一行“指令”主题,并将 href 设置为“#!/Angular/3”,以便参数 3 在……中传递。 URL.
步骤 2)在路由提供程序服务函数中添加主题 ID
在路由提供程序服务函数中,添加 :topicId 占位符,表示传入的任何参数 URL 路由之后应将其分配给变量 topicId。
步骤 3)向控制器添加必要的代码
- 定义控制器函数时,请务必先添加“$routeParams”作为参数。此参数将可以访问所有传入的路由参数。 URL.
- “$routeParams”保存了路由中传递的topicId。附加
$routeParams.topicId范围$scope.tutorialid使其在视图中作为 tutorialid 可用。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Event Registration</title> </head> <body ng-app="sampleApp"> <script src="https://code.angularjs.org/1.8.3/angular.min.js"></script> <script src="https://code.angularjs.org/1.8.3/angular-route.js"></script> <h1> Guru99 Global Event</h1> <table class="table table-striped"> <tbody> <tr><td>1</td><td>Controllers</td> <td><a href="#!/Angular/1">Topic details</a></td></tr> <!-- rows 2 and 3 repeat with /Angular/2 and /Angular/3 --> </tbody> </table> <div ng-view></div> <script> var sampleApp = angular.module('sampleApp', ['ngRoute']); sampleApp.config(['$routeProvider', function($routeProvider) { $routeProvider. when('/Angular/:topicId', { templateUrl: 'Angular.html', controller: 'AngularController' }); }]); sampleApp.controller('AngularController', ['$scope', '$routeParams', function($scope, $routeParams) { $scope.tutorialid = $routeParams.topicId; }]); </script> </body> </html>
⚠️ 已进行更正。 原文使用了字母 l 而不是数字 1 in href="#Angular/l"省略了 ng-view 容器导致模板无处渲染,并且加载完毕。 angular-route.js before angular.min.js这会抛出一个模块错误。
步骤 4)添加表达式以显示变量
添加表达式以在 Angular.html 页面中显示 tutorialid 变量。
<h2>Angular</h2> <br><br>{{tutorialid}}
如果代码执行成功,在浏览器中运行代码时将显示以下输出。
输出:
在输出屏幕中,
- 如果您点击第一个主题的“主题详情”链接,数字 1 将被附加到主题名称后。 URL.
- 该数字将作为“routeParams”参数,并在控制器中可访问。
读取参数很简单。接下来要介绍的属性负责在视图显示之前,获取参数所标识的记录。
如何使用 resolve 属性预加载数据
上一节中的控制器读取主题 ID 并立即显示。实际应用必须先从服务器获取记录,如果视图在请求返回之前渲染,用户将看到一个空白模板,稍后才会填充内容。 resolve 该属性可以消除空白内容的闪烁。
每把钥匙都在 resolve 该对象是 AngularJS 在路由激活前准备的一个依赖项。如果该值是一个 Promise,路由器会等待它完成解析。只有当所有 Promise 都解析完毕后,AngularJS 才会实例化控制器并渲染模板,并将解析后的值按名称注入到控制器中,就像其他任何服务一样。
sampleApp.config(['$routeProvider', function($routeProvider) { $routeProvider. when('/Angular/:topicId', { templateUrl: 'Angular.html', controller: 'AngularController', resolve: { // The router waits for this promise before rendering topic: ['$http', '$route', function($http, $route) { var id = $route.current.params.topicId; return $http.get('/api/topics/' + id).then(function(response) { return response.data; }); }] } }); }]); // 'topic' is injected already resolved, so no loading state is needed sampleApp.controller('AngularController', ['$scope', 'topic', function($scope, topic) { $scope.topic = topic; }]);
这里有两个行为至关重要。被拒绝的 Promise 会取消路由更改,并使浏览器停留在当前视图,因此失败的请求不会导致页面显示异常。然而,由于路由器会在 Promise 等待期间阻塞,因此响应缓慢的端点会导致应用程序看起来像是卡住了。 resolve 进度指标由以下因素驱动: $routeChangeStart 和 $routeChangeSuccess 事件。
⚠️ 警告: 切勿仅在内部设置身份验证检查 resolve拒绝路由会隐藏视图,但不会保护其背后的数据,API 端点仍然必须在服务器上强制执行访问权限。
除了预加载数据之外,路由还可以携带静态配置值。接下来介绍的服务将说明控制器如何读取这些配置值。
如何使用 Angular $route 服务
`$route` 服务允许您访问路由的属性。当在控制器中定义函数时,`$route` 服务可以作为参数使用。下面展示了如何从控制器中提供 `$route` 参数的一般语法。
myApp.controller('MyController', function($scope, $route) { ... });
- myApp 是为您的应用程序定义的 AngularJS 模块。
- MyController 是为您的应用程序定义的控制器的名称。
- 就像 $scope 将信息从控制器传递到视图一样,$route 公开当前路由的属性。
让我们来看看如何使用 $route 服务。
在这个例子中,
- 我们将创建一个名为“mytext”的简单自定义变量,它将包含字符串“This is angular”。
- 我们将把这个变量附加到我们的路由上。 Later 我们将使用 $route 服务从控制器访问此字符串,然后使用作用域对象将其显示在视图中。
那么,让我们看看实现这一目标需要执行的步骤。
步骤1) 向路由添加自定义键值对。在这里,我们添加一个名为“mytext”的键,并为其分配一个值“This is angular”。
步骤2) 将相关代码添加到控制器中。
- 在控制器函数中添加 `$route` 参数。`$route` 参数是 Angular 中定义的一个关键参数,它允许访问路由的属性。
- 可以通过 $route.current 引用访问在路由中定义的“mytext”变量。然后将其分配给范围对象的“text”变量。然后可以从视图中相应地访问文本变量。
// Only the config and controller change; the page markup is unchanged sampleApp.config(['$routeProvider', function($routeProvider) { $routeProvider. when('/Angular/:topicId', { mytext: "This is angular", // custom key attached to the route templateUrl: 'Angular.html', controller: 'AngularController' }); }]); sampleApp.controller('AngularController', ['$scope', '$routeParams', '$route', function($scope, $routeParams, $route) { $scope.tutorialid = $routeParams.topicId; $scope.text = $route.current.mytext; }]);
步骤3) 从范围对象中添加对文本变量的引用作为表达式。这将添加到我们的 Angular.html 页面,如下所示。
这将导致文本“This is angular”被注入到视图中。 {{tutorialid}} 表达式与上一个主题中看到的表达式相同,这将显示数字“1”。
<h2>Angular</h2> <br><br>{{text}} <br><br>{{tutorialid}}
如果代码执行成功,在浏览器中运行代码时将显示以下输出。
输出:
从输出来看,
- 我们可以看到,当我们点击表格中的任何链接时,文本“This is angular”也会显示出来。主题 ID 也会与文本同时显示。
所有的 URL 目前显示的内容仍然带有#符号。最后的配置步骤会将其移除。
启用 HTML5 路由
HTML5路由用于创建清晰的路由。 URL这意味着从……中删除井号标签。 URL所以,路由 URL当使用 HTML5 路由时,s 将如下所示。
示例.html/Angular/1
示例.html/Angular/2
示例.html/Angular/3
这个概念通常被称为呈现一个漂亮的 URL 给用户。
HTML2 路由需要执行 5 个主要步骤。
- 配置 $locationProvider
- 设置相对链接的基础
让我们详细看一下如何在示例中执行上述步骤。
步骤1) 将相关代码添加到Angular模块中。
- 添加
<base>在文档头部添加标签。这是 HTML5 路由所必需的,以便应用程序知道其基本位置。 - 添加 $locationProvider 服务。此服务允许您定义 html5Mode。
- 将$locationProvider服务的html5Mode设置为true。
步骤2) 移除所有链接('Angular/1'、'Angular/2'、'Angular/3')的 # 标签,以创建易于阅读的文本。 URLs.
<!-- In the head: required by html5Mode so relative templates resolve --> <base href="/"> <!-- In the body: the # is dropped from every link --> <a href="Angular/1">Topic details</a> <script> sampleApp.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) { $locationProvider.html5Mode(true); $routeProvider. when('/Angular/:topicId', { templateUrl: 'Angular.html', controller: 'AngularController' }); }]); </script>
⚠️ 更正: 原件声明 baseUrl 始终指向本地 IDE 路径,这对 html5Mode 没有影响。AngularJS 从此处读取基本位置。 <base href> 标签。原件也注入了。 $locationProvider 从未打电话 html5Mode(true)因此,哈希值从未被删除。
如果代码执行成功,在浏览器中运行代码时将显示以下输出。
输出:
从输出来看,
- 您可以看到,访问应用程序时没有#标签。
以上所有示例均使用了 AngularJS 团队提供的路由工具 ngRoute。但这并非唯一选择,下面的对比将说明何时使用其他方案更为合适。
ngRoute 与 ui-router:该选择哪个路由器
ngRoute 由 AngularJS 团队维护,并且与……匹配 URL 直接指向单个模板和控制器。ui-router 是一个社区项目,旨在消除 ngRoute 的主要限制:它会在应用程序上进行匹配。 州 而不是在 URL 单独使用,即可在一个屏幕上包含多个独立路由的区域。
| 方面 | ngRoute | ui-router |
|---|---|---|
| 配置服务 | 路由提供程序 | $stateProvider |
| 比赛 | URL 仅由 | 命名州, URL 可选 |
| 嵌套视图 | 不支持 | 支持 |
| 每个屏幕多个视图 | 一个 ng-view | 许多名为 ui-view outlets |
| 嵌套解析 | 不支持 | 子状态继承父状态解析 |
| 最适合 | 扁平、小型应用 | 仪表盘和分层布局 |
选择 ngRoute 时 URL 由于它不需要额外的依赖项,并且整个 API 都放在一个页面上,因此它映射到一个全页视图。当屏幕包含可以独立导航的窗格,或者子视图需要重用父视图加载的数据时,请选择 ui-router。以后迁移是可能的,但并非易事,因为状态名称会被替换。 URL 模板中贯穿各种图案。
常见的AngularJS路由错误及解决方法
大多数路由故障会导致 ng-view 页面空白,而不是控制台报错,这使得故障诊断比预期更难。以下每种症状都列出了其原因和解决方法。
- 未知提供商:$routeProvider: angular-route.js 从未加载,或者加载时间早于 angular.min.js。请先引用核心库。
- 页面一片空白,没有报错: 没有元素带有 ng-view 指令,因此模板没有地方可以渲染。
- 首次访问时没有任何内容加载: 没有路由匹配空路径。添加一个 otherwise 代码块,并设置 redirectTo 值。
- $routeParams 为空: 该模式缺少冒号占位符。它必须写成“/Angular/:topicId”。
- html5Mode 后出现 404 模板错误: 配置服务器将不匹配的路径重写到基本页面,并确认基本 href 标签存在。
- 控制器从不重新运行: 只有参数发生了变化,所以 AngularJS 重用了控制器实例,而不是重新构建它。监听 `$routeUpdate` 事件,而不是依赖控制器函数再次触发。
























