我试图相信文档网站上写的内容。然而,它似乎并不完全正确,或者实现已经更新但文档没有更新。
简单来说:
First, CanDeactivate
警卫被检查从最深到顶部 and CanActivate
警卫被检查从上到最深(它会quit遍历中存在错误检查)。
Second, CanActivateChild
警卫不接受检查从最深到顶部.
TL;DR
详细说明
我们应该检查源代码,看看它是如何工作的。
注意:检查的提交是:https://github.com/angular/angular/tree/edb8375a5ff15d77709ccf1759efb14091fa86a4 https://github.com/angular/angular/tree/edb8375a5ff15d77709ccf1759efb14091fa86a4
第 1 步 - 查看何时CanActivateChild
接到电话
来源在这里 L929 https://github.com/angular/angular/blob/edb8375a5ff15d77709ccf1759efb14091fa86a4/packages/router/src/router.ts#L929.
这只是其上级调用者的地方runCanActivateChild
被叫了。
在这一行,我们可以得到一些提示,它与CanActivate
, 因为CanActivate
的上级来电者runCanActivate
之后被调用。
第 2 步 - 看看效果如何runCanActivateChild
work
L926 https://github.com/angular/angular/blob/edb8375a5ff15d77709ccf1759efb14091fa86a4/packages/router/src/router.ts#L926 and L950 https://github.com/angular/angular/blob/edb8375a5ff15d77709ccf1759efb14091fa86a4/packages/router/src/router.ts#L950.
runCanActivateChild
在迭代中被调用canActivateChecks
,与如何runCanActivate
被叫了。在这里我们知道CanActivate
(我的意思是功能)和CanActivateChild
共享相同的数据源——canActivateChecks
.
第 3 步 - 什么是canActivateChecks
以及它是如何被处理的
那么,什么是canActivateChecks
?显然,我们可以发现它是一个数组CanActivate
类实例。但怎么样canActivateChecks
被分配了?到这里 L865 https://github.com/angular/angular/blob/edb8375a5ff15d77709ccf1759efb14091fa86a4/packages/router/src/router.ts#L865。这是重要的部分,所以我将它们粘贴在这里。
private traverseChildRoutes(
futureNode: TreeNode<ActivatedRouteSnapshot>, currNode: TreeNode<ActivatedRouteSnapshot>|null,
contexts: ChildrenOutletContexts|null, futurePath: ActivatedRouteSnapshot[]): void {
const prevChildren = nodeChildrenAsMap(currNode);
// Process the children of the future route
futureNode.children.forEach(c => {
this.traverseRoutes(c, prevChildren[c.value.outlet], contexts, futurePath.concat([c.value]));
delete prevChildren[c.value.outlet];
});
// Process any children left from the current route (not active for the future route)
forEach(
prevChildren, (v: TreeNode<ActivatedRouteSnapshot>, k: string) =>
this.deactivateRouteAndItsChildren(v, contexts !.getContext(k)));
}
private traverseRoutes(
futureNode: TreeNode<ActivatedRouteSnapshot>, currNode: TreeNode<ActivatedRouteSnapshot>,
parentContexts: ChildrenOutletContexts|null, futurePath: ActivatedRouteSnapshot[]): void {
const future = futureNode.value;
const curr = currNode ? currNode.value : null;
const context = parentContexts ? parentContexts.getContext(futureNode.value.outlet) : null;
// reusing the node
if (curr && future._routeConfig === curr._routeConfig) {
if (this.shouldRunGuardsAndResolvers(
curr, future, future._routeConfig !.runGuardsAndResolvers)) {
this.canActivateChecks.push(new CanActivate(futurePath));
const outlet = context !.outlet !;
this.canDeactivateChecks.push(new CanDeactivate(outlet.component, curr));
} else {
// we need to set the data
future.data = curr.data;
future._resolvedData = curr._resolvedData;
}
// If we have a component, we need to go through an outlet.
if (future.component) {
this.traverseChildRoutes(
futureNode, currNode, context ? context.children : null, futurePath);
// if we have a componentless route, we recurse but keep the same outlet map.
} else {
this.traverseChildRoutes(futureNode, currNode, parentContexts, futurePath);
}
} else {
// ##### comment by e-cloud #####
if (curr) {
this.deactivateRouteAndItsChildren(currNode, context);
}
this.canActivateChecks.push(new CanActivate(futurePath));
// If we have a component, we need to go through an outlet.
if (future.component) {
this.traverseChildRoutes(futureNode, null, context ? context.children : null, futurePath);
// if we have a componentless route, we recurse but keep the same outlet map.
} else {
this.traverseChildRoutes(futureNode, null, parentContexts, futurePath);
}
}
}
有点长。但如果你仔细看一遍你就会发现它的作用深度优先遍历。我们忽略相同的路由切换。寻找##### comment by e-cloud #####
并查看主要程序。它表明它更新了canActivateChecks
先进行下一级遍历(整体前序遍历)。
你必须知道路由器将应用程序的所有路由视为 url 树。每个PreActivation
分裂它的future
(作为树路径)进入路径段通过遍历。
Take a 简化的例子:
我们未来的路线是/a/b/c
.
然后我们将得到 [ '/a', '/a/b', '/a/b/c' ] 作为canActivateChecks
显然,canActivateChecks
表示从顶部到最深处的路线future
消息来源显示canActivateChecks
从左到右迭代。
第 4 步 - 结论
我们可以得出结论CanActivateChild
是从顶部到最深的孩子。
希望我解释清楚。