3

Angular RouterModule.forRoot(ROUTES) 和 forChild(ROUTES)的区别

 1 year ago
source link: https://blog.51cto.com/jerrywangsap/5919630
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

不少 Angular 初学者在学习 Angular 路由框架时,对 forRootforChild 这两个方法的差异都 心生疑惑

Angular 官网对两个方法的解释:

  • forRoot 创建一个包含所有指令、给定路由和路由器服务本身的模块。

  • forChild 创建一个包含所有指令和给定路由的模块,但不包含路由器服务。

但缺乏具体的例子。

Module with providers

当我们导入模块时,通常使用的是对模块类的引用。

@NgModule({
    providers: [AService]
})
export class A {}

-----------------------------------

@NgModule({
    imports: [A]
})
export class B

通过这种方式,所有在模块 A 上注册的 Service Providers 都将被添加到根注入器中,并可用于整个应用程序。

另一种方式也能工作:

@NgModule({
    providers: [AService]
})
class A {}

export const moduleWithProviders = {
    ngModule: A,
    providers: [AService]
};

----------------------

@NgModule({
    imports: [moduleWithProviders]
})
export class B

我们知道延迟加载模块有自己的注入器。 因此,假设我们要注册 AService 以供整个应用程序使用,但某些 BService 仅可用于延迟加载的模块。 可以像这样重构模块:

@NgModule({
    providers: [AService]
})
class A {}

export const moduleWithProvidersForRoot = {
    ngModule: A,
    providers: [AService]
};

export const moduleWithProvidersForChild = {
    ngModule: A,
    providers: [BService]
};

------------------------------------------

@NgModule({
    imports: [moduleWithProvidersForRoot]
})
export class B
    
// lazy loaded module    
@NgModule({
    imports: [moduleWithProvidersForChild]
})
export class C

这样一来,Service B 将仅对子延迟加载模块可用,而 Service A 将对整个应用程序可用。

上述代码可以进一步重构为:

@NgModule({
    providers: [AService]
})
class A {
    forRoot() {
        return {
            ngModule: A,
            providers: [AService]
        }
    }

    forChild() {
        return {
            ngModule: A,
            providers: [BService]
        }
    }
}

--------------------------------------

@NgModule({
    imports: [A.forRoot()]
})
export class B

// lazy loaded module
@NgModule({
    imports: [A.forChild()]
})
export class C

当我们通过同一个 injection token 获得 Service 的引用实例时,事情就变得更有趣了。

export const moduleWithProvidersForRoot = {
    ngModule: A,
    providers: [{provide: token, useClass: AService}]
};

export const moduleWithProvidersForChild = {
    ngModule: A,
    providers: [{provide: token, useClass: BService}]
};

当从延迟加载的模块使用单独的配置来请求 token 时,我们将获得 Service B 的实例引用。

RouterModule 使用 ROUTES 令牌获取特定于模块的所有路由。 因为它希望特定于延迟加载模块的路由在该模块内可用(类似于我们之前讨论的 Service B),所以它对延迟加载的子模块使用不同的配置:

static forChild(routes: Routes): ModuleWithProviders {
    return {
        ngModule: RouterModule, 
        providers: [{provide: ROUTES, multi: true, useValue: routes}]
    };
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK