角度守卫,文档中的声明不明确

2024-05-07

我想深入了解角度,所以我读了the docs http://angular.io这非常有帮助。
现在我正在研究守卫。我在文档中读到了这个声明。

路由器首先从最深的子路由到顶部检查 CanDeactivate 和 CanActivateChild 防护。然后它从上到下检查 CanActivate 守卫到最深的子路线。

现在我很困惑,为什么 Angular 会以这种方式执行它?
从最深的孩子到顶部进行检查有什么好处可以停用 & 可以激活子项。以及从顶部到最深的子路线可以激活?


我试图相信文档网站上写的内容。然而,它似乎并不完全正确,或者实现已经更新但文档没有更新。

简单来说:

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是从顶部到最深的孩子。

希望我解释清楚。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

角度守卫,文档中的声明不明确 的相关文章

  • 元素不适应 Firefox 上的

    使用 ES6 ish D3js 模块运行 Angular 6 应用程序会导致 Firefox 出现问题 Chromium Chrome Safari 和 IE Edge 工作正常 伪代码看起来类似于 生产代码可以在下面找到
  • 415 不支持的媒体类型; Angular2 到 API

    我是 Angular 2 的新手 我面临着一个无法找到解决方案的问题 当我尝试从 Angular 2 发布到 API 时 我得到 415 不支持的媒体类型 角度2代码 onSubmit value any console log value
  • 如何显示 GroupList 的 FormArray?

    我正在尝试制作一个交互式表单 在每一行上列出一个项目以及一个删除按钮 在我的示例中称为 verwijderen 这些项目是从数据库中检索的 并且每个项目都实例化为名为的自定义对象LaborPeriod 然后这些对象被转化为FormGroup
  • Angular 5 - 在加载数据之前停止未定义对象的错误

    防止控制台中因仍未定义的对象而出现错误的最佳方法是什么 假设我有这个 name string constructor private data DataService this data name subscribe res gt this
  • 使用 Nginx 在 Docker 容器内部署带有路由器的 Angular2

    我正在尝试部署一个使用框架的路由器功能的 Angular 2 但在 docker 容器内使用 nginx 为其提供服务时遇到一些问题 由 angular cli 构建的 Angular 应用程序具有如下文件结构 dist 08c42df75
  • 如何转义角度 HttpParams?

    在 Angular 服务中 我使用 HttpParams 将字符串发送到服务 get phone string Observable
  • 将 Angular Web 组件 EventEmitter 监听到 javascript

    我在以下工具的帮助下创建了一个小型网络组件本文 https medium com IMM9O web components with angular d0205c9db08f使用角度元素 其中包括 Input and Output 我能够将
  • Angular 以什么方式解决重复的指令/组件选择器?

    如果我包含两个模块 它们都使用相同的选择器定义组件或指令 可以说a routerLink ModuleA 使用选择器定义指令a routerLink ModuleB 使用选择器定义指令a routerLink AppModule 包括模块和
  • 如何禁用 ng2-dragula 上的某些元素的拖动

    我想在顶部显示名称组并取消其上的拖动事件 如何禁用移动某些元素 例如该组名称位于顶部 我的代码是 dragulaService drag subscribe value gt console log drag value 0 我的模板 di
  • 角度垫排序不适用于带点表示法的 matColumnDef

    我正在尝试按列对表进行排序 当我必须过滤另一个结果中的结果时 就会出现问题 我尝试通过括号表示法和点表示法访问该属性 但没有给出结果 还将最终节点放置在 matColumnDef 中 但失败 因为有 2 列同名 table table
  • 如何调试超时等待异步 Angular 任务?无法在角度页面上找到元素

    编辑 请注意 在 ernst zwingli 的帮助下 我找到了问题的根源 因此 如果您遇到相同的错误 他指出的修复之一可能会帮助您 我的问题是量角器本身的一个已知问题 如果您认为这可能是您 我已经扩展了我的步骤 以在我最初的问题之后查明问
  • Angular 2:基于环境导入服务

    根据 Angular CLI 项目中的当前环境导入服务的最佳 正确方法是什么 我已经设置了一个名为 dev mock 的新环境 我可以使用它来调用 ng serve environment mock 然后我使用 useClass 在模块中设
  • Angular 2 获取当前路线

    所以我需要以某种方式检查我是否在主页上执行某些操作 而在其他页面上则不执行此操作 该组件也在所有页面上导入 如果我在主页上 如何检测该组件 Thanks 尝试这个 import Router from angular router expo
  • 如何在 Angular 项目中使用 Bootstrap?

    我开始我的第一次Angular应用程序和我的基本设置已完成 我怎样才能添加引导程序我的申请 如果您可以提供一个示例 那么这将是一个很大的帮助 如果您使用Angular CLI要生成新项目 还有另一种方法可以使 bootstrap 可访问角度
  • 如何将窗口注入到服务中?

    我正在用 TypeScript 编写一个 Angular 2 服务 它将利用localstorage 我想注入对浏览器的引用window对象到我的服务中 因为我不想引用任何全局变量 例如 Angular 1 x window 我怎么做 这目
  • Angular 7:ng 测试挂起,不断重复运行测试

    我最近将 Angular 6 应用程序迁移到角7 my 包 json看起来像这样 name myApp version 3 0 0 license MIT scripts ng ng start ng serve public host h
  • 收到错误 ../node_modules/rxjs/Rx"' 没有导出成员 'of'

    我正在从教程中学习新的角度 https angular io tutorial toh pt4 inject message service https angular io tutorial toh pt4 inject message
  • 无法读取未定义的“触及”属性

    为什么我会收到此错误无法读取未定义的属性 为什么无法读取formName controls email touched但它能够阅读formName get custDetails touched
  • 找不到“节点”的类型定义文件

    更新 Angular Webpack 和 TypeScript 后出现奇怪的错误 知道我可能会错过什么吗 当我使用 npm start 运行应用程序时 出现以下错误 at loader Cannot find type definition
  • 如何让 vsCode 了解自动补全的深度依赖导入?

    我创建了多个角度库 让我可以使用一堆组件更快地创建网站 例如 sidenav 卡片 我创建了一个 超级库 来导入所有这些库 这样我就可以使用npm i myWebsiteBundle立即下载所有依赖项 我已将每个类似的插件列入白名单ng p

随机推荐