为什么Angular中的子组件应该通过NgModule注册?封装怎么样?

ten*_*its 11 angular

我对其他框架和架构原则有一些经验,我绝对不理解Angular团队决定directivies在RC6中弃用Component 的属性而转而支持declarationsNgModule.

通常,体系结构是关于封装的,但是如果组件的某些功能性应该由子组件封装,则子组件"泄漏"到模块,现在应该注册.

  1. 那么为什么在模块中有一个组件的逻辑树,所有这些都应该在NgModule中注册"普通"?

  2. 这种方法是否不会导致大量进口和退出的ngmodule?

我知道我们可以将所有内容拆分为多个模块,但在单个模块中,这样的全局"加载和注册"会让我记住script [src]html中的一堆全局标记.我以为我们已经离开了这个模式,但看起来像Angular回归它.

看来,我想念一下,有人可以解释一下吗?


[ 编辑1 ](打破AOT编译,请参阅edit-2)现在,我们模仿嵌套组件声明,以便每个组件导出使用过的组件列表,然后在NgModule中我们遍历所有根组件,收集它们的依赖关系并准备完整declarations列表.

它看起来像这样:

src/app    
    - /components/home-view/
        - /toolbar
            /menu-button
                - menu-button.component.ts

            - toolbar.component.ts

        - home-view.component.ts

    - app.module.ts
Run Code Online (Sandbox Code Playgroud)

app.module.ts

import { HomeViewComponent } from './components/home-view/home-view.component';

namespace Utils {
    export function flatternDirectives (arr: any[] = []): any[] {
        const declarations = arr.reduce((compos, compo) => {
            compos.push(...flatternDirectives(compo.directives), compo);
            return compos;
        }, []);
        return Array.from(new Set(declarations));
    }
}
@NgModule({
    declarations: Utils.flatternDirectives([
        HomeViewComponent,    
    ]),
    bootstrap: [AppComponent]
})
export class AppModule { }
Run Code Online (Sandbox Code Playgroud)

./components/home-view/home-view.component.ts

import { ToolbarComponent } from './toolbar/toolbar.component';

@Component({
    selector: 'app-home-view',
    template: `<app-toolbar></app-toolbar>`,    
})
export class HomeViewComponent {
    static directives = [ ToolbarComponent ]
}
Run Code Online (Sandbox Code Playgroud)

./components/home-view/toolbar/toolbar.component.ts

import { MenuButtonComponent } from './menu-button/menu-button.component';

@Component({
    selector: 'app-toolbar',
    template: `<app-menu-button></app-menu-button>`,    
})
export class ToolbarComponent {
    static directives = [ MenuButtonComponent ]
}
Run Code Online (Sandbox Code Playgroud)

./components/home-view/toolbar/menu-button/menu-button.component.ts

@Component({
    selector: 'app-menu-button',
    template: `<button></button>`,    
})
export class MenuButtonComponent {}
Run Code Online (Sandbox Code Playgroud)

这种方法有什么警告吗?


[ 编辑2 ]在DEV中,上面的方法工作正常,但AOT编译打破了错误.

ERROR in : Cannot determine the module for class 'name' in 'path'! Add 'name' to the NgModule to fix it.
Run Code Online (Sandbox Code Playgroud)

所以我们必须回到平原宣言.任何解决方案如何tofix aot编译?

谢谢.

kem*_*sky 5

  1. NgModule概念在发布之前就已经发布了,它提供了创建库/模块的标准方法,增加了有效的导入系统和延迟加载功能.在许多方面,它类似于任何其他模块/包系统(即声明模块依赖,模块公共导出等),由于JS性质而具有一些限制.

  2. 您可以在设计模块时选择粒度级别,以避免详细的导入/声明.库倾向于使用每个组件的模块策略来最小化大小影响(您只需导入所需的内容,不再需要),但有时您必须导入许多模块.

  3. 问题是在AOT中,所有组件引用必须在编译期间静态解析,因此不能使用动态代码,例如flatternDirectives函数,因为它不是静态可分析的.请参阅https://angular.io/guide/aot-compiler#metadata-restrictions,我怀疑是否可以编写可删除重复条目的函数,但可能您甚至可以使用重复的条目,即declarations: [HomeViewComponent.directives](需要检查生成的代码) .

  • 1.您可以浏览NgModule的angular api页面,例如有`declaration`字段,angular无法自动检测模块内部使用的组件,`entryComponents`必须包含要动态创建的组件。在其他UI框架中通常不需要这种注册。2.如果您不想创建库或不使用延迟加载,则可以使用1个模块。如果需要,可以创建其他任何适合您需要的模块结构。3.可能是我认为是编译器优化。 (2认同)