ngRoute 和 ui.router 的使用方法和區別


在單頁面應用中要把各個分散的視圖給組織起來是通過路由機制來實現的。本文主要對 AngularJS 原生的 ngRoute 路由模塊和第三方路由模塊 ui.router 的用法進行簡單介紹,並做一個對比。

ngRoute

使用方法

1) 引入 angular-route lib

無論是 ngRoute 還是 ui.router ,作為框架額外的附加功能,都必須以 模塊依賴 的形式被引入。

1
<script src="lib/angular-route.js"></script>

2) 配置路由

1
2
3
4
5
6
7
8
9
var app = angular.module('ngRouteApp', ['ngRoute']);

app.config(function($routeProvider){
$routeProvider
.when('/Main', {
templateUrl: "main.html",
controller: 'MainCtrl'
})
.otherwise({ redirectTo: '/tabs' });

服務與指令

ngRoute 路由模塊名

$routeProvider 服務提供者,用來定義一個路由表,即地址欄與視圖模板的映射,對應於ui.router 中的 urlRouterProvider 和 stateProvider

$route 服務,完成路由匹配,並且提供路由相關的屬性訪問及事件,如訪問當前路由對應的 Controller,對應於下面的 $urlRouter 和 $state
$routeParams 服務,保存了地址欄中的參數,對應於下面的 $stateParams

ng-view 指令,用來在主視圖中指定加載子視圖的區域,對應於下面的 ui-view

ui.router

使用方法

1) 引入 angular-ui-router lib

1
<script src="lib/angular-ui-router.min.js"></script>

2) 配置路由

1
2
3
4
5
6
7
8
9
10
var app = angular.module("uiRouteApp", ["ui.router"]);

app.config(function($urlRouterProvider, $stateProvider) {
$urlRouterProvider.otherwise("/index");
$stateProvider
.state("Main", {
url: "/main",
templateUrl: "main.html",
controller: 'MainCtrl'
})

服務與指令

ui.router 路由模塊名

$urlRouterProvider 服務提供者,用來配置路由重定向
$stateProvider 服務提供者,用來配置路由

$urlRouter 服務
$state 服務,用來顯示當前路由狀態信息,以及一些路由方法(如:跳轉)
$stateParams 服務,用來存儲路由匹配時的參數

ui-view 指令,路由模板渲染,對應的 dom 相關聯
ui-sref 指令,鏈接到特定狀態

路由的創建

基本配置

調用 $stateProvider.state(...) 方法,並可配置以下參數

1
2
3
4
5
6
$stateProvider
.state("Main", {
url: "/main",
templateUrl: 'main.html',
controller: 'MainCtrl',
})

parent

有兩種方式可以指定父子狀態關系。

一種是,使用點標記法,像本文最后嵌套視圖部分舉得栗子那樣:

1
.state("tabs.tab1", {})

另一種是,使用 parent 屬性

1
2
3
.state("tab1", {
parent: 'tabs' // 也可是一個狀態對象, parent: tabs
})

abstract

使用 abstract 可以為所有的子狀態提供一個基 URL,這樣做的好處就是可以在抽象出來的這個狀態所對應的 html 頁面中來定義靜態資源。抽象模板不能被激活。

1
2
3
4
5
6
7
8
9
10
$stateProvider
.state('contacts', {
abstract: true,
url: '/contacts',
templateUrl: 'contacts.html',
})
.state('contacts.list', {
url: '/list',
templateUrl: 'contacts.list.html'
})

resolve

resolve 在 state 配置參數中,是一個對象(key-value),每一個 value 都是一個可以依賴注入的函數,並且返回的是一個 promise (當然也可以是值)。

1
2
3
4
5
6
resolve: {
'myResolve': ['contacts',
function(contacts){
return contacts.all();
}]
}

這樣做的目的:

  • 簡化了 controller 的操作,將數據的獲取放在 resolve 中進行,這在多個視圖多個controller 需要相同數據時,有一定的作用。
  • 只有當 reslove 中的 promise 全部 resolved(即數據獲取成功)后,才會觸發$stateChangeSuccess 切換路由,進而實例化 controller,然后更新模板。

更多參數可參考 angular 系列八 ui-router詳細介紹及ngRoute工具區別 中 state 參數的講解。

路由控制

url 動態部分被稱為參數,有以下幾種方式設置

1) 使用花括號的方式可以設置一個正則表達式規則的參數:

1
2
//只會匹配 pageId 為1到8位的數字
url: "/pages/{pageId:[0-9]{1,8}}"

可以通過 ? 來指定參數作為查詢參數

1
2
//比如匹配 href="/page?type='new'"
url: "/page?type"

如果需要不止一個查詢參數,用 & 分隔:

1
2
//比如匹配 ui-sref="page({type:'all', title:'test ui-router'})"
url: "/page?type&title"

路由的查找匹配

  • angular 在剛開始的 $digest 時,$rootScope 會觸發 $locationChangeSuccess 事件(angular 在每次瀏覽器 hash change 的時候也會觸發 $locationChangeSuccess 事件)
  • ui.router 監聽了 $locationChangeSuccess 事件,於是開始通過遍歷一系列 rules,進行路由查找匹配列表項
  • 當匹配到路由后,就通過 $state.transitionTo(state,...),跳轉激活對應的 state
  • 最后,完成數據請求和模板的渲染

在視圖中,建議使用 ui-sref="xxxState" 而不是 href="#/abc",這樣做能減少一遍 rules循環的遍歷,提升性能。

兩者區別

ngRoute模塊 是 Angular 自帶的路由模塊,而 ui.router模塊 是基於 ngRoute模塊 開發的第三方模塊。

ui.router 是基於 state(狀態)的, ngRoute 是基於 url 的,ui.router模塊 具有更強大的功能,主要體現在視圖的嵌套方面。

嵌套視圖

頁面某個動態變化區塊中,嵌套着另一個可以動態變化的區塊。

前面的栗子就是一個很好的業務場景。

在首頁中包含一個動態區塊:

1
2
3
4
<body ng-app="ngRouteApp">
<h3>AngularJS UI-Router Tabs</h3>
<div ng-view></div>
</body>

在標簽頁中又包含動態區塊:

1
2
3
4
5
6
<div>
<span><a href="#/tab1">Page-1</a></span>
<span><a href="#/tab2">Page-2</a></span>
<span><a href="#/tab3">Page-3</a></span>
</div>
<div ng-view></div>

一運行,報了一個這樣的錯誤:

RangeError: Maximum call stack size exceeded 

發現瀏覽器崩潰了,因為 ng-view 會陷入死循環,無限遞歸下去。

使用 ui.router 能很容易解決這個問題,因為它定義的路由有明確的父子關系,並通過 ui-view 指令將子路由模版插入到父路由模板的 <div ui-view></div> 中去,從而實現視圖嵌套。看代碼:

1
2
3
4
5
6
7
8
9
$stateProvider
.state("tabs", {
url: "/tabs",
templateUrl: "pageTab.html"
})
.state("tabs.tab1", {
url: "/tab1",
templateUrl: "tab1.html"
})

其他區別

ui-router(左) : ngRoute(右)

  • 應用程序內的一個區域 : 應用程序中的 url
  • 可以嵌套的層次結構 : 只是平面層次結構
  • 名稱可以自定義 : 名稱只能是 url
  • 通過名稱或 url 導航 : 只能通過 url 導航
  • 可以存在多個視圖(ui-view) : 只能單一視圖(ng-view)
  • 可以填充任何視圖 : 只能填充一個視圖
  • 通過狀態填充某一部件 : 通過指令將填充某一部件

參考

  1. ui.router源碼解析
  2. AngularJS ui-router (嵌套路由)
  3. ngRoute VS ui-router
  4. angular的uiRouter服務學習


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM