Angular2 RC6 Route学习
前言
Angularjs2終于最新的week Conf沒有顯示會出現RC7,也就意味著下次就是stable了,不會有break changes了。閑話少說。 路由的功能在SPA應用的地位無可置疑,angularjs1的ng-route由于難以實現多層路由而基本被ui-route取代,angular2則改變了這一現狀,開始支持嵌套路由,還設置了UrlTree。我們一起來看一下吧。(PS.以下內容basehref默認’\’,例子筆者盡量選擇官方例子)
首先,要能知道我們先看什么后看文件,去github上看一下,我們大致分下類:
首先就是index.ts文件,作為@angular/router 的入口文件,里面提供了好多router內的export,不過都是選擇性的一些export類型和方法,當然也會包含RouterModule的部分類型和方法。筆者認為基本上index.ts就是router的全部內容。
其次,核心的,也就是import也很多的route_module.ts文件,看名字就是知道,封裝成RouterModule讓我們用的。其中提供了一堆的const,咱們只看export的,有ROUTER_CONFIGURATION及ROUTER_FORROOT_GUARD以及ROUTER_PROVIDERS: Provider[]和集大成者class RouterModule,class RouterModule 其constructor(@Optional() @Inject(ROUTER_FORROOT_GUARD) guard: any) {} 只有一個裝飾器。module有兩個重要的靜態方法static forRoot(routes: Routes, config?: ExtraOptions): ModuleWithProviders 及static forChild(routes: Routes): ModuleWithProviders 。這兩個方法都返回ModulewithProviders,結果就是返回一個選定的ngModule和一個注射器providers[],來對構造函數的裝飾器進行注射實例化。providers數組里面不是useFactory用的就是我們用的。剩下就是一些optional方法讓我們繼續深度配置router,這段話有點邏輯混亂。整理來說route_module.ts文件,通過構造函數里面的一個類symbol類裝飾器來提供給我們一堆的依賴注入(providers[]),結果就是實例化一個RouterModule時,選擇forRoot和forChildern都會返回一堆依賴關系實例,這一大堆實例中我們就舉其中一個例子,讓大家感受下這個RouterModule里的依賴關系的多和復雜:forRoot中provider了一個ROUTER_PROVIDERS,這是一個provider[],其中又provider了一個Router,然后這個Router是使用setupRouter進行實例化(useFactory),其中又依賴了deps:[ApplicationRef,UrlSerializer,RouterOutletMap,Location,Injector,NgModuleFactoryLoader,Compiler, ROUTES, ROUTER_CONFIGURATION],最終得到了一個Router類的實例。更不用說多重provide(multi: true在forRoot與forChildren中都有的provideRoutes(routes: Routes) 中使用)以及@Self(或@SkipSelf)的使用了。不管怎么樣,這一個Module基本就是我們angular2的路由精華所在了,要什么有什么。看不懂沒關系,回頭再看源代碼就感覺RouterModule就是個紙老虎,真正的內容都是它import的內容。
緊隨這兩個文件之后,也是這兩個文件都import的router.ts,是路由的真實核心文件,config.ts是實用文件。后者為前者的一個構造函數屬性。
在之后就是基礎,我稱之為材料文件的:router_state.ts,interface.ts,shared.ts,url_tree.ts
最后就是我稱之為工具文件的:directives文件夾(里面包含三個指令)及utils文件夾(一個collection一個tree),create_router_state.ts,create_url_tree.ts,router_config_loader.ts,router_outlet_map.ts,apply_redirects.ts和private_export.ts
我們自上而下來看,先看最簡單的config.ts文件,其核心就是routes(或route)。
Routes
Routes-an array of route configurations-Route[]
我們通過import { Routes } from ' @angular/router';來導入angular2為我們提供的路由進行我們的路由配置,首先我們看一下Routes為我們準備了什么:
path* is a string that uses the route matcher DSL.
path也就是我們的URL,可選屬性有”、’**’、’team:id’,但不允許’\’。其中由于”是所有url的前綴(見pathMatch),在路由配置時要注意
pathMatch is a string that specifies the matching strategy.
這個匹配策略屬性一般被設置為full用來匹配”的情況,與redirectTo一起(僅能)使用來進行默認地址(即’\’)的設置,還有一個屬性為prefix,前綴匹配(默認)。
component is a component type.
選擇進行渲染的組件,有父組件、子組件和主組件、輔組件(見outlet)
redirectTo is the url fragment which will replace the current matched segment.
重定向,如果屬性字符串前面有’\’如’\user\23’則表示絕對地址。
outlet is the name of the outlet the component should be placed into.
相當于Angularjs1中的ng-view,組件渲染的目的地址,可選屬性:’aux’,即輔助outlet,在設置此屬性時要配置primary和aux outlet,此時可稱為無父組件路由,達到了兄弟組件間分享路由參數的目的
canActivate is an array of DI tokens used to look up CanActivate handlers.
canActivateChild is an array of DI tokens used to look up CanActivateChild handlers.
canDeactivate is an array of DI tokens used to look up CanDeactivate handlers.
data is additional data provided to the component via ActivatedRoute.
字符串數組,提供給相應的渲染組件
resolve is a map of DI tokens used to look up data resolvers.
字符串數組,將data解析
children is an array of child route definitions.Route[]數組,顯而易見,children可以進行層層嵌套
因為Routes是Route[],我們通過interface Route小溫習一下:
export interface Route {path?: string;pathMatch?: string;component?: Type<any>;redirectTo?: string;outlet?: string;canActivate?: any[];canActivateChild?: any[];canDeactivate?: any[];canLoad?: any[];data?: Data;resolve?: ResolveData;children?: Route[];loadChildren?: LoadChildren;} 注:a Type is a MyCustomComponent class舉個小例子:
[{path: 'team/:id',component: Team,children: [{path: '',component: WrapperCmp,children: [{path: 'user/:name',component: User}]}]}]當我們訪問 /team/11/user/jim, 路由就會實例化wrapper component with the user component in it.
結束了以上基礎,我們基本可以深入angular2的Route去了。
繼續Routes
首先,在上面的行程中,我們有幾個概念或者說是疑惑:
-data、resolve到底在component中怎么使用的
-canActivate與其他相似的那幾個是什么,作用如何
-canLoad與loadChildren是什么,作用如何
讓我們前往router/router_state.ts和router/interfaces.ts以及router.ts開始探索吧
注:其實沒有import interfaces.ts里面的那幾個函數,我們就看看同名接口的定義,主要還是router.ts和route_state.ts里面的類及方法,下段可以跳過。
首先是interface里面的定義:
interfaces.ts文件: import {Route} from './config';
import {ActivatedRouteSnapshot, RouterStateSnapshot} from './router_state';沒有工具文件,只import了這兩個材料文件。
關于LoadChildren要多說幾句,從下面代碼可以看出來,LoadChildren不僅表現為一個字符串,而且還可以表現為Type,這就有意思了,我上文提到過,一個Type就是一個component類的class。這樣我們可以通過LoadChildren來導入子路由,而不是在一個route文件里把所有的父子路由都表示出來(充滿了children的層層嵌套),只找到了LoadChildren的type定義。在config.ts文件中,對Data,ResolveData,LoadChildren及LoadChildrenCallBack進行了類型定義,供其他文件進行引用。
LoadChildren:
export type LoadChildren = string | LoadChildrenCallback;export type LoadChildrenCallback = () => Type<any>| Promise<Type<any>>| Observable<Type<any>>;然后是route_state.ts中的定義:
route_state.ts文件:import {Data, ResolveData, Route} from './config';import {PRIMARY_OUTLET, Params} from './shared';除了工具文件就引用了這兩個材料文件。
Contains the information about a component loaded in an outlet at a particular moment in time.即包含已在一個outlet中渲染的組件的某一時刻信息:
export class ActivatedRouteSnapshot {_routeConfig: Route;_urlSegment: UrlSegmentGroup;_lastPathIndex: number;_resolve: InheritedResolve;_routerState: RouterStateSnapshot;constructor(public url: UrlSegment[], public params: Params, public queryParams: Params,public fragment: string, public data: Data, public outlet: string,public component: Type<any>|string, routeConfig: Route, urlSegment: UrlSegmentGroup,lastPathIndex: number, resolve: InheritedResolve) {this._routeConfig = routeConfig;this._urlSegment = urlSegment;this._lastPathIndex = lastPathIndex;this._resolve = resolve;} get routeConfig(): Route { return this._routeConfig; } get root(): ActivatedRouteSnapshot { return this._routerState.root; } get parent(): ActivatedRouteSnapshot { return this._routerState.parent(this); } get firstChild(): ActivatedRouteSnapshot { return this._routerState.firstChild(this); } get children(): ActivatedRouteSnapshot[] { return this._routerState.children(this); } get pathFromRoot(): ActivatedRouteSnapshot[] { return this._routerState.pathFromRoot(this); }toString(): string {const url = this.url.map(s => s.toString()).join('/');const matched = this._routeConfig ? this._routeConfig.path : '';return `Route(url:'${url}', path:'${matched}')`;} }The state of the router at a particular moment in time.即Router某個時刻的狀態,由下可知,就是組件信息樹:
export class RouterStateSnapshot extends Tree<ActivatedRouteSnapshot> {constructor(public url: string, root: TreeNode<ActivatedRouteSnapshot>) {super(root);setRouterStateSnapshot<RouterStateSnapshot, ActivatedRouteSnapshot>(this, root);}toString(): string { return serializeNode(this._root); } } function setRouterStateSnapshot<U, T extends{_routerState: U}>(state: U, node: TreeNode<T>): void {node.value._routerState = state;node.children.forEach(c => setRouterStateSnapshot(state, c)); } function serializeNode(node: TreeNode<ActivatedRouteSnapshot>): string {const c = node.children.length > 0 ? ` { ${node.children.map(serializeNode).join(", ")} } ` : '';return `${node.value}${c}; 基本就是ActiveRouted類和RouterState類的翻版,這四個類兩兩基本可以等效使用(不是等價)。
接下來是router.ts文件中的聲明:
在Route構造函數中,canActivate是任意類型的。canActivate中文官網被翻譯為路由守衛,功能是對路由跳轉進行權限限制,通俗來講就是沒登錄你就不能去這個地址,沒相應等級授權你也不許去。
走向router.ts
我們終于倉促的看完一部分重要文件,出于現在有點小開心,就直接來看router.ts這大boss吧。
前提import {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot, advanceActivatedRoute, createEmptyState} from './router_state';import {NavigationCancelingError, PRIMARY_OUTLET, Params} from './shared'; 除了工具文件,就引用了這兩個材料文件。
首先我們要明確,這個文件能夠提供給我們最大的用處是哪里:
今日上午先寫到這,要休息一下,一會再填坑~~
筆者能力有限,如有錯誤及遺漏請各位批評指正!
總結
以上是生活随笔為你收集整理的Angular2 RC6 Route学习的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 信息安全之网络安全初体验(保密向)(一)
- 下一篇: 自用零散博文-route_state.t