在企業應用中權限、複雜頁多路由數據處理、進入與離開路由數據處理這些是很是常見的需求。typescript
當但願用戶離開一個正常編輯頁時,要中斷並提醒用戶是否真的要離開時,若是在Angular中應該怎麼作呢?瀏覽器
其實Angular路由守衛屬性能夠幫咱們作更多有意義的事,並且很是簡單。antd
Angular 的 Route
路由參數中除了熟悉的 path
、component
外,還包括四種是否容許路由激活與離開的屬性。app
canActivateide
控制是否容許進入路由。this
canActivateChildspa
等同 canActivate
,只不過針對是全部子路由。code
canDeactivatecomponent
控制是否容許離開路由。server
canLoad
控制是否容許延遲加載整個模塊。
例如:
{ path: 'logics', loadChildren: './logics/logics.module#LogicsModule', canLoad: [ AuthGuard ] }
這四個屬性很是好理解,並且做用各自不一樣。而後當進入與離開可以有效控制權時,對於前面我提到的若干問題,就能夠很是好的處理。
四個屬性雖然名稱不一樣,但其基本的使用方式很是相近。四種不一樣守衛方式有者四個不一樣的接口與之相對應。
屬性名 | 接口名 |
---|---|
canActivate |
CanActivate |
canActivateChild |
CanActivateChild |
canDeactivate |
CanDeactivate<TComponent> |
canLoad |
CanLoad |
canDeactivate
須要指明具體的組件類名之外,其餘接口只是將首字母大寫而已。假定須要一個某個角色才能訪問某些路由,就須要一個 CanActivate
守衛類。
@Injectable() export class CanAdminProvide implements CanActivate { constructor(private userSrv: UserService, private msg: NzMessageService) {} canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | Observable<boolean> | Promise<boolean> { return new Observable((observer) => { // 擁有 `admin` 角色 if (this.userSrv.hasRole('admin')) { observer.next(true); observer.complete(); return; } this.msg.error('受權不足'); observer.next(false); observer.complete(); }); } }
每種接口要都須要相應的實現某個方法,就上而論,繼承 CanActivate
並實現一個叫 canActivate
的方法;且返回一個布爾類型的值。
四種類型守衛接口都返回一個布爾類型值,其實從這四種參數的名稱 can
開頭就否則理解。
最後,把它運用到相應的路由上便可,例如:
{ path: 'admin', component: GuardAdminComponent, canActivate: [ CanAdminProvide ] }
固然,別忘記註冊 CanAdminProvide
類。
四種守衛只有一種離開類型 canDeactivate
,所以:
@Injectable() export class CanLeaveProvide implements CanDeactivate<GuardComponent> { constructor (private confirmSrv: NzModalService) {} canDeactivate( component: GuardComponent, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState?: RouterStateSnapshot): boolean | Observable<boolean> | Promise<boolean> { return new Observable((observer) => { this.confirmSrv.confirm({ title: '確認要離開嗎?', content: '你已經填寫了部分表單離開會放棄已經填寫的內容。', okText: '離開', cancelText: '取消', onOk: () => { observer.next(true); observer.complete(); }, onCancel: () => { observer.next(false); observer.complete(); } }); }); } }
這裏返回的是一個 Observable
類型,意味者,在方法體內能夠作任何事,只須要在結果中使用:
// 容許 observer.next(true); // 或拒絕 // observer.next(false); observer.complete();
來處理 Observable
的結果,就完成了整個流程。假若,用戶按瀏覽器後退或路由至其餘頁面時,會先收到一個提醒。
上面使用的 ng-zorro-antd 的確認對話框來提醒用戶是否須要離開,若選擇【離開】則跳轉至目標路由,反之保留當前路由狀態。
這是再正常不過的功能,若用戶進入一個未受權的路由時,甚至是某個遲延加載模塊下全部路由;若用戶無權限時,如何提醒用戶。
此時 canActivate
、canLoad
就有用了。假定管理員角色才能加載管理模塊下全部管理功能以及某個管理頁面,基於接口多繼承的特性,能夠同時繼承這兩個接口。
@Injectable() export class CanAuthProvide implements CanActivate, CanLoad { constructor(private userSrv: UserService, private msg: NzMessageService) {} check(): Observable<boolean> { return new Observable((observer) => { if (this.userSrv.isLogin) { observer.next(true); observer.complete(); return; } this.msg.error('權限不足'); observer.next(false); observer.complete(); }); } canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | Observable<boolean> | Promise<boolean> { return this.check(); } canLoad(route: Route): boolean | Observable<boolean> | Promise<boolean> { return this.check(); } }
所以,一個類中具備兩種不一樣守衛的能力,更對於代碼組織也更優雅。一樣,須要運用到相應的路由當中。
{ path: 'auth', component: GuardAuthComponent, canActivate: [ CanAuthProvide ] }, { path: 'admin', loadChildren: './admin/admin.module#AdminModule', canLoad: [ CanAuthProvide ] }
此後,若一個普通員工帳號要想進入(哪怕瀏覽器地址欄錄入)未受權的路由 /auth
會提示 權限不足
的字樣。
路由守衛對於權限控制很是便利,固然其粒度固然只能在頁面層級。假若須要對按鈕粒度也只能利用指令的方式,而兩者的結合能夠極大的改善權限控制埋點的代碼量。
Happy coding!