Ответ 1
Я пытался поверить в то, что написано на сайте docs. Тем не менее, кажется, что это не совсем правильно, или реализация была обновлена, но документы не обновляются.
Чтобы быть кратким:
Во-первых, защита CanDeactivate
проверяется от самого глубокого до верхнего уровня и CanActivate
проверяется защита сверху до глубины (она будет выйти с ложной проверкой обхода).
Во-вторых, защита CanActivateChild
не проверяется с глубины доверху.
TL; DR
Подробное описание
мы должны проверить источник, чтобы узнать, как он работает.
Примечание. Проверенная фиксация: https://github.com/angular/angular/tree/edb8375a5ff15d77709ccf1759efb14091fa86a4
шаг 1 - см., когда CanActivateChild
получил вызов
Это только место, которое вызывал его главный вызывающий абонент runCanActivateChild
.
В этой строке мы можем получить некоторый намек на то, что он делает тот же трюк, что и CanActivate
, потому что CanActivate
старший вызывающий runCanActivate
вызывается после.
шаг 2 - посмотрите, как работает runCanActivateChild
runCanActivateChild
вызывается внутри итерации canActivateChecks
, так же, как и вызываемый runCanActivate
. Здесь мы знаем CanActivate
(я имею в виду функцию) и CanActivateChild
используют один и тот же источник данных - canActivateChecks
.
шаг 3 - что такое canActivateChecks
и как он обрабатывается
Итак, что такое canActivateChecks
? Очевидно, мы можем найти массив массивов экземпляров класса CanActivate
. Но как назначить canActivateChecks
? Перейдите сюда 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
(как путь к дереву) на сегменты пути путем обхода.
Возьмите упрощенный пример:
у нас есть будущий маршрут как
/a/b/c
.
Тогда мы получим ['/a', '/a/b', '/a/b/c'] какcanActivateChecks
По-видимому, canActivateChecks
представляет маршруты от вершины до самой глубины future
Источник показывает, что canActivateChecks
повторяется слева направо.
шаг 4 - заключение
мы можем заключить, что CanActivateChild
выполняется от вершины до самого глубокого.
Надеюсь, я объясню это ясно.