如何使用ui-router


如何使用ui-router?_騰訊視頻



【JS-6】

如何使用ui-router?

小課堂【武漢分院第137期】

分享人:徐恒

目錄

1.背景介紹

2.知識剖析

3.常見問題

4.解決方案

5.編碼實戰

6.擴展思考

7.參考文獻

8.更多討論

一.背景介紹

angular路由

路由(route),幾乎所有的MVC(VM)框架都應該具有的特性,因為它是前端構建單頁面應用(SPA)必不可少的組成部分。

那么,對于angular而言,它自然也有內置的路由模塊:叫做ngRoute。

不過,大家很少用它,因為它的功能太有限,往往不能滿足開發需求!!

于是,一個基于ngRoute開發的第三方路由模塊,叫做ui.router,受到了大家的“追捧”。

ngRoute vs ui.router

首先,無論是使用哪種路由,作為框架額外的附加功能,它們都將以模塊依賴的形式被引入,簡而言之就是:在引入路由源文件之后,你的代碼應該這樣寫(以ui.router為例):

angular.module("myApp", ["ui.router"]); // myApp為自定義模塊,依賴第三方路由模塊ui.router

這樣做的目的是:在程序啟動(bootstrap)的時候,加載依賴模塊(如:ui.router),將所有掛載在該模塊的服務(provider),指令(directive),過濾器(filter)等都進行注冊,那么在后面的程序中便可以調用了。

說到這里,就得看看ngRoute模塊和ui.router模塊各自都提供了哪些服務,哪些指令?

ngRoute

$routeProvider(服務提供者) ——— 對應于下面的urlRouterProvider和stateProvider

$route(服務) ——— 對應于下面的urlRouter和state

$routeParams(服務) ——— 對應于下面的stateParams

ng-view(指令) ——— 對應于下面的ui-view

ui.router

$urlRouterProvider(服務提供者) ——— 用來配置路由重定向

$urlRouter(服務)

$stateProvider(服務提供者) ——— 用來配置路由

$state(服務) ——— 用來顯示當前路由狀態信息,以及一些路由方法(如:跳轉)

$stateParams(服務) ——— 用來存儲路由匹配時的參數

ui-view(指令) ——— 路由模板渲染,對應的dom相關聯

ui-sref(指令)

(注:服務提供者:用來提供服務實例和配置服務。)

這樣一看,其實ui.router和ngRoute大體的設計思路,對應的模塊劃分都是一致的(畢竟是同一個團隊開發),不同的地方在于功能點的實現和增強。

那么問題來了:ngRoute弱在哪些方面,ui.router怎么彌補了這些方面?

這里,列舉兩個最重要的方面來說(其他細節,后面再說):

多視圖

嵌套視圖

多視圖

多視圖:頁面可以顯示多個動態變化的不同區塊。

這樣的業務場景是有的:

比如:頁面一個區塊用來顯示頁面狀態,另一個區塊用來顯示頁面主內容,當路由切換時,頁面狀態跟著變化,對應的頁面主內容也跟著變化。

首先,我們嘗試著用ngRoute來做:

html

區塊1

區塊2

js$routeProvider? ? .when('/', {? ? ? ? template: 'hello world'? ? });

我們在html中利用ng-view指令定義了兩個區塊,于是兩個div中顯示了相同的內容,這很合乎情理,但卻不是我們想要的,但是又不能為力,因為,在ngRoute中:

視圖沒有名字進行唯一標志,所以它們被同等的處理。

路由配置只有一個模板,無法配置多個。

ok,針對上述兩個問題,我們嘗試用ui.router來做:

html

js$stateProvider? ? .state('home', {? ? ? ? url: '/',? ? ? ? views: {? ? ? ? ? ? '': {? ? ? ? ? ? ? ? template: 'hello world'? ? ? ? ? ? },? ? ? ? ? ? 'status': {? ? ? ? ? ? ? ? template: 'home page'? ? ? ? ? ? }? ? ? ? }? ? });

這次,結果是我們想要的,兩個區塊,分別顯示了不同的內容,原因在于,在ui.router中:

可以給視圖命名,如:ui-view=”status”。

可以在路由配置中根據視圖名字(如:status),配置不同的模板(其實還有controller等)。

注:視圖名是一個字符串,不可以包含@(原因后面會說)。

嵌套視圖

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

這樣的業務場景也是有的:

比如:頁面一個主區塊顯示主內容,主內容中的部分內容要求根據路由變化而變化,這時就需要另一個動態變化的區塊嵌套在主區塊中。

其實,嵌套視圖,在html中的最終表現就像這樣:

I am parent

I am child

轉成javascript,我們會在程序里這樣寫:$routeProvider? ? .when('/', {? ? ? ? template: 'I am parent

I am child

'? ? });

倘若,你真的用ngRoute這樣寫,你會發現瀏覽器崩潰了,因為在ng-view指令link的過程中,代碼會無限遞歸下去。

那么造成這種現象的最根本原因:路由沒有明確的父子層級關系!

看看ui.router是如何解決這一問題的?

$stateProvider? ? .state('parent', {? ? ? ? abstract: true,? ? ? ? url: '/',? ? ? ? template: 'I am parent

'? ? })? ? .state('parent.child', {? ? ? ? url: '',? ? ? ? template: 'I am child'? ? });

巧妙地,通過parent與parent.child來確定路由的父子關系,從而解決無限遞歸問題。

另外子路由的模板最終也將被插入到父路由模板的div[ui-view]中去,從而達到視圖嵌套的效果。

記住下面是ui.router用到的所有指令

ui.router

$urlRouterProvider(服務提供者) ——— 用來配置路由重定向

$urlRouter(服務)

$stateProvider(服務提供者) ——— 用來配置路由

$state(服務) ——— 用來顯示當前路由狀態信息,以及一些路由方法(如:跳轉)

$stateParams(服務) ——— 用來存儲路由匹配時的參數

ui-view(指令) ——— 路由模板渲染,對應的dom相關聯

ui-sref(指令)

初級應用(會用就行)

介紹用這個例子($urlRouter和$stateParams沒用到,其他都用到:$urlRouterProvider,$stateProvider,$state,ui-view,ui-sref)

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'

})

})

首先給大家介紹angular-ui-router的基本用法。

如何引用依賴angular-ui-router就是

再從簡單的開始(其實這幾個服務也都是有依賴的,例如$urlRouterProvider依賴$urlMatcherFactoryProvider? $locationProvider。$urlRouterProvider依賴$urlRouterProvider $urlMatcherFactoryProvider。但初級應用這不展開,只講要用到某幾個方法(不是全部))

$urlRouteProvider(總共3個when,otherwise和rule)這里懂when和otherwise就行。

$urlRouteProvider.when(whenPath, toPath)

為給定的URL匹配注冊一個處理程序。

$urlRouterProvider.otherwise(path)

定義一個當請求的路徑是無效路徑時跳轉的路徑。

例子:就用到一種情況(當請求的路徑是無效路徑時跳轉的路徑)

$urlRouterProvider

.otherwise('/login');

// .when("","/login");

$stateProvider(總共2個方法:decorator和state。但這里只講state(state這個里面的配置也不講全的,只講幾個暫時用到的))

處理路由狀態的服務,路由的狀態反映了該項在應用程序中的位置,描述了在當前狀態下UI是應該怎么樣的,并且該做什么。

方法:

state(name,stateConfig);

注冊一個狀態,并給定其配置。

//state可以有子父級

$stateProvider.state("home",{});

$stateProvider.state("home.child",{})

//state可以是鏈式的

$stateProvider.state("home",{}).state("about",{}).state("photos",{});

參數:

name:狀態的名稱。

stateConfig:狀態配置對象。配置具有以下各項屬性(全部屬性,看一下好了):

template: string/function,html模板字符串,或者一個返回html模板字符串的函數。

templateUrl:string/function,模板路徑的字符串,或者返回模板路徑字符串的函數。

templateProvider:function,返回html模板字符串或模板路徑的服務。

controller:string/function,新注冊一個控制器函數或者一個已注冊的控制器的名稱字符串。

controllerProvider:function,返回控制器或者控制器名稱的服務

controllerAs:string,控制器別名。

parent:string/object,手動指定該狀態的父級。

resolve:object,將會被注入controller去執行的函數,string,function>形式。

url:string,當前狀態的對應url。

views:object,視圖展示的配置。string,object>形式。

abstract:boolean,一個永遠不會被激活的抽象的狀態,但可以給其子級提供特性的繼承。默認是true。

onEnter:function,當進入一個狀態后的回調函數。

onExit:function,當退出一個狀態后的回調函數。

reloadOnSearch:boolean,如果為false,那么當一個search/query參數改變時不會觸發相同的狀態,用于當你修改$location.search()的時候不想重新加載頁面。默認為true。

data:object,任意對象數據,用于自定義配置。繼承父級狀態的data屬性。換句話說,通過原型繼承可以達到添加一個data數據從而整個樹結構都能獲取到。

params:url里的參數值,通過它可以實現頁面間的參數傳遞。

這里用到了

url:string,當前狀態的對應url。

params:url里的參數值,通過它可以實現頁面間的參數傳遞。

template: string/function,html模板字符串,或者一個返回html模板字符串的函數。

templateUrl:string/function,模板路徑的字符串,或者返回模板路徑字符串的函數。

resolve:object,將會被注入controller去執行的函數,string,function形式。

例子:

$stateProvider

.state("login",{

url: "/login",

templateUrl: "tpls/login.html",

resolve:{

load:['$ocLazyLoad',function($ocLazyLoad){

return $ocLazyLoad.load([

'css/login.css',

'js/login.js'

]);

}]

}

})

進一步

.state("main.article-list",{

url: "/article-list/:page/:size/:startAt/:endAt/:type/:status",

params:{'page':"1",'size':"10"},

templateUrl: "tpls/article-list.html",

resolve:{

load:['$ocLazyLoad',function($ocLazyLoad){

return $ocLazyLoad.load([

'css/article-list.css',

'js/article-list.js'

]);

}]

}

})

再說下

$state(總共6個方法和1個事件:go,href,include,is,reload,transitionTo和事件:$stateChangeError,$stateChangeStart,$stateChangeSuccess和$stateNotFound。這里只要會go就行)

$state服務負責代表狀態及提供狀態之間的轉換。它還提供你當前的狀態及上一個狀態。

方法:

go(to,params,options);

參數:

to:string,即將跳轉的狀態。

params:object,跳轉所帶的參數。

options:object,可選配置對象。有 location(是否更新地址欄的url,或以什么字符串替換url),inherit(是否繼承當前url的參數),relative(當變化相對路徑:如"^,定義的狀態是相對的),notify(是否廣播$stateChangeStart和$stateChangeSuccess事件),reload(是否重新載入)。

實例:

$state.go("login");

跳轉到在前面中定義的狀態那里

$stateProvider

.state("login",{})

然后就是^和.的用法區別,一個是向上一級,一個向下一級

$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.comment

ui-sref(2種,一種不帶參數,一種帶)

一種將鏈接(a標簽)綁定到一個狀態的指令。點擊該鏈接將觸發一個可以帶有可選參數的狀態轉換。

ui-sref="stateName"ui-sref="stateName({param:value,param:value})"代碼:首頁你的主頁

ui-view

一種是沒有名字的

一種是有名字的

來一個demo1

項目文件結構

node_modules/ //這里放各種依賴

partials/? ? //這里放跳的頁面

.....about.html

.....home.html

.....photos.html

app.js? ? ? //寫router

index.html

index.html文件? 就是一個導航欄(注意這里有ui-sref的跳轉)+一個ui-view(當然是跳轉后的各個頁面的東西)+依賴

Home

Photos

About

app.js? 寫的ui.router

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'

})

})

更進一步就是task6-10(低版本)

router.js

var myApp = angular.module("myApp",['ui.router','oc.lazyLoad','ngMessages','tm.pagination']);

myApp.config(function ($stateProvider,$urlRouterProvider) {

$urlRouterProvider

.otherwise('/login');

// .when("","/login");

$stateProvider

.state("main.article-list",{

url: "/article-list/:page/:size/:startAt/:endAt/:type/:status",

params:{'page':"1",'size':"10"},

templateUrl: "tpls/article-list.html",

resolve:{

load:['$ocLazyLoad',function($ocLazyLoad){

return $ocLazyLoad.load([

'css/article-list.css',

'js/article-list.js'

]);

}]

}

})

});

上面用到了url的參數,params的參數,以及resolve。當然后面會用到$stateParams。

url中的/:page/:size/在params中初始化,然后傳參數過去。resolve中的是懶加載。

上面URL傳過來的參數在article-list.js中用到(分頁插件用的),通過$stateParams獲取。

article-list.js

var listApp = angular.module("myApp",[]);

listApp.controller("listCtrl",['$scope','$http','$state','$stateParams',function ($scope,$http,$state,$stateParams) {

// 分頁部分

$scope.paginationConf = {

showFlag:0,

// 當前頁

currentPage: 1,

// 每頁默認

itemsPerPage: 10,

// 點擊每個分頁按鈕都會觸發這個函數,然后刷新加載

onChange:function () {

console.log('$scope.paginationConf.currentPage=' );

console.log($scope.paginationConf.currentPage );

console.log('$scope.paginationConf.itemsPerPage=');

console.log($scope.paginationConf.itemsPerPage);

$state.go('main.article-list', {

page: $scope.paginationConf.currentPage ,

size: $scope.paginationConf.itemsPerPage

}, {reload: true});

}};

console.log('$stateParams=' );

console.log($stateParams );

$scope.paginationConf.currentPage = $stateParams.page ;

$scope.paginationConf.itemsPerPage = $stateParams.size ;

二.知識剖析

三.常見問題

四.解決方案

五.代碼實戰

六.拓展思考

七.參考文獻

ui.router源碼解析

AngularJS ui-router (嵌套路由)

angular的uiRouter服務學習

$stateParams服務

八.更多討論

鳴謝

感謝大家觀看

BY : 徐恒




1.ngRoute能做到多視圖嵌套么

2.ng-view能命名么

3.ui-router這么多參數常用的是那些?

4.還有哪些情況下是適合ngRoute使用的



------------------------------------------------------------------------------------------------------------------------

技能樹.IT修真院

“我們相信人人都可以成為一個工程師,現在開始,找個師兄,帶你入門,掌控自己學習的節奏,學習的路上不再迷茫”。

這里是技能樹.IT修真院,成千上萬的師兄在這里找到了自己的學習路線,學習透明化,成長可見化,師兄1對1免費指導。快來與我一起學習吧 !

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容