exportconstTodoRoutes: Route[] = [ { path: 'todo', children: [ { path: 'list', component: TodoListComponent }, { path: 'detail/:id', component: TodoDetailComponent } ] } ];
在路径 todo 下面,有两个子路由,分别是列表和详情。
然后再针对下面的需求,一个个来解决:
所有的todo模块的页面都需要用户角色
离开详情页需要确认
进入列表页面之前需要先获取任务列表数据
控制所有todo模块的都需要用户角色
对于第一个,我们要保护所有的todo模块的页面,也就是'/todo'路径的所有子路径,所以,我们可以使用 CanActivateChild 。这样,在每进入一个todo的子路径的时候,都会先进行检查来判断能否进入。代码如下:
import{ Injectable }from'@angular/core'; import{ CanActivateChild, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from'@angular/router'; import{ AuthService }from'../services/auth.service'; import{ TodoDetailComponent }from'./detail/detail.component'; @Injectable() exportclassMyTodoGuardimplementsCanActivateChild{ constructor(private authService: AuthService, private router: Router) {} canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot) { if(!this.authService.isLogdedin()) { alert('You need to login!'); this.router.navigate(['/home']); returnfalse; } if(this.authService.hasRole('CUSTOMER')) { returntrue; } returnfalse; } }
这个 Guard 的实现很简单,就是用 authService 来判断是否登陆,以及是否具有'CUSTOMER'角色。
注意这个 Guard 的实现也必须是 Injectable 的,因为我们需要Angular的依赖注入帮我们创建实例和自动注入。
离开详情页需要确认
接下来我们看怎么实现离开详情页时的确认,也很简单,就是使用 CanDeactivate ,并把它定义在详情页的路由定义上。
@Injectable() exportclassCanLeaveTodoDetailGuardimplementsCanDeactivate<TodoDetailComponent>{ canDeactivate(component: TodoDetailComponent, route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { returnconfirm('Confirm?'); } }
为了简单,上面的方法直接调用 confirm('confirm?') 并返回它的结果,它会返回一个布尔型的结果,表示用户是否确认。如果用户取消了,就不会离开详情页。
进入列表页面之前需要先获取数据
最后,再看看用 Resolve 来实现进入一个页面之前的数据初始化。
import{ Injectable }from'@angular/core'; import{ Resolve, ActivatedRouteSnapshot, RouterStateSnapshot }from'@angular/router'; import{ Todo }from'./todo'; import{ TodoService }from'./todo.service'; @Injectable() exportclassMyTodoResolverimplementsResolve<Todo>{ constructor(private todoService: TodoService) { } resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { console.log('Get my todo list.'); returnthis.todoService.getAllTodos(); } }
在这个 resolve() 方法中,直接返回调用 todoService 的 getAllTodos() 方法的结果。对这个 getAllTodos() 方法我们做一些修改,让他返回一些测试数据:
import{ Observable }from'rxjs/Observable'; import'rxjs/add/observable/of'; import'rxjs/add/operator/delay'; // 神略中间的部分 getAllTodos(): Observable<Todo[]> { lettodo1 =newTodo(); todo1.id = 1; todo1.title = 'test task 1'; todo1.createdDate = newDate(); todo1.complete = false; lettodo2 =newTodo(); todo2.id = 2; todo2.title = 'test task 2'; todo2.createdDate = newDate(); todo2.complete = false; this.todos = [todo1, todo2]; returnObservable.of(this.todos).delay(3000); }
在这个方法里我们创建了2个测试的任务,封装成 Observable 返回,并添加了一个3秒钟的延时,来模拟从服务器端获取数据的过程。
通过 Resolve 方式获取的数据,会放在被激活的当前路由的 data 属性里面,我们可以在组件中来获得。所以,需要修改 TodoListComponent ,从路由的数据 data 中获取 todos 的值。然后就可以在页面中显示:
exportclassTodoListComponent{ newTodo: Todo = newTodo(); todos: Todo[]; constructor(private todoService: TodoService, private route: ActivatedRoute) { this.todos =this.route.snapshot.data['todos']; } // 省略其他 }
最终的todo模块路由配置
最后我们再看看加上上面的 Guard 和 Resolve 的路由配置以后,todo模块的路由配置: