为什么 <app-root> 在其中渲染另一个 <app-root>,其中包含我的路由组件?

Why is <app-root> rendering another <app-root> within it, which contains my routed component?

我有一个延迟加载的多模块 Angular 7.2.2 应用程序,它似乎在自身内部创建主 AppComponent 模板的副本,然后渲染路由组件在那里面。

这是我对完整而简洁的序言的尝试(我无法在 plunkr 中重现)。请询问我遗漏的任何细节。

序言

我有一个 index.html 文件,其中包含普通 HTML 和 <body> 中的 <app-root> 元素。这是项目中唯一出现 app-root 标记的地方。此文件在 angular.jsonprojects.app.architect.build.options.index 属性.

中引用

主要AppComponent声明为

@Component({
  selector: 'app-root',
  template: `
    <router-outlet></router-outlet>
    <message-banner [show]="showMessage" [message]="message"></message-banner>
  `,
  providers: [AuthenticationService, AuthenticationGuard, MessagingService]
})

AppComponent 中的其余逻辑只是调节 showmessage 应用程序范围通知的内容。我没有路由器插座连接,也没有直接 DOM 操作。

我的 main.ts 像往常一样引导应用程序

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app.module';
import { environment } from './environments/environment';

import { hmrBootstrap } from './hmr';

if (environment.production) {
  enableProdMode();
}

const bootstrap = () => platformBrowserDynamic().bootstrapModule(AppModule);

if (environment.hmr && module['hot']) {
  hmrBootstrap(module, bootstrap);
}
else {
  bootstrap().catch(err => console.log(err));
}

来自以下AppModule

@NgModule({
  imports: [
    appRoutes,
    BrowserAnimationsModule,
    BrowserModule,
    CommonModule,
    FormsModule,
    HttpClientModule,
    HttpClientXsrfModule,
    ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }),
    SharedGenericModule
  ],
  declarations: [
    AppComponent,
    MessageBannerComponent
  ],
  providers: [
    { provide: APP_BASE_HREF, useValue: '/' },
    appRoutingProviders,
    ChoosePasswordGuard,
    LoadingBarService,
    Title,
    UserService
  ],
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  bootstrap: [AppComponent]
})

export class AppModule {}

使用这些 app.routes(小摘录)

const routes: Routes = [
  {
    path: '',
    redirectTo: 'shop',
    pathMatch: 'full'
  },
  {
    path: '',
    component: AppComponent,
    children: [
      {
        path: 'shop',
        data: { key: 'shop' },
        loadChildren: "./modules/shop.module#ShopModule",
        pathMatch: 'full'
      },
      {
        path: 'car/:id',
        data: { key: 'car' },
        loadChildren: "./modules/car.module#CarModule",
        pathMatch: 'full'
      },
      {
        // This one has child routes, which I will add if needed
        path: 'workOrder',
        data: { key: 'workOrder' },
        loadChildren: "./modules/workOrder.module#WorkOrderModule",
      }
      // And many more
    ]
  }
]

export const appRoutes: ModuleWithProviders = RouterModule.forRoot(routes, {
  enableTracing: false,
  onSameUrlNavigation: 'reload'
});

问题

应用程序稳定后,结果 DOM 如下所示:

<body>
  <app-root ng-version="7.2.2">

    <router-outlet></router-outlet>

    <app-root>
      <router-outlet></router-outlet>
      <default-routed-component _nghost-c0>...</default-routed-component>
      <message-banner ng-reflect-show="true" ng-reflect-message="[object Object]">...</message-banner>
    </app-root>

    <message-banner ng-reflect-show="true" ng-reflect-message="[object Object]">...</message-banner>

  </app-root>
</body>

请注意,内部 <app-root> 未使用 ng-version 修饰。

此外,我只能以编程方式与内部 <message-banner> 通信,外部似乎已断开连接。但是在加载第一个路由之前(在应用程序稳定之前)生成的消息被发送到 both 个消息横幅实例。

问题

为什么我的应用程序实例化两个 <app-root> 和两个 <router-outlets>,但只使用其中一个。我怎样才能阻止它这样做?

我需要在整个应用程序范围内保留一个 <message-banner>,但我显然想要 一个 。如果不是因为该组件的重复,它可能只是一个神秘的不便 - 该应用程序在其他方面都运行良好。

回想起来答案非常明显。

AppComponent - 包含应用程序唯一的 <router-outlet> 和我想在整个应用程序中使用的通用代码 - 从主 AppModule 并由路由器第二次实例化作为默认路由的组件,然后将功能模块加载为子路由。

修复只是删除了 AppComponent 和子路由;所以要从

更改 app.routes.ts
const routes: Routes = [
  {
    path: '',
    redirectTo: 'shop',
    pathMatch: 'full'
  },
  {
    path: '',
    component: AppComponent,
    children: [
      {
        path: 'shop',
        data: { key: 'shop' },
        loadChildren: "./modules/shop.module#ShopModule",
        pathMatch: 'full'
      },
  ...
  }
]

const routes: Routes = [
  {
    path: '',
    redirectTo: 'shop',
    pathMatch: 'full'
  },
  {
    path: 'shop',
    data: { key: 'shop' },
    loadChildren: "./modules/shop.module#ShopModule",
    pathMatch: 'full'
  },
  ...
]

我是新手,我不明白为什么,但你应该用另一个 <router-outlet> 标签创建另一个主要组件(除了 app.component.ts - 这是主要组件)和从父路由中调用它。例如

第一步: ng 生成 c layout/inicio

App
 - Layout
     -inicio.component.ts
     -inicio.component.html

这就是魔法 =>

代码:inicio.component.ts

const routes: Routes = [
  {
    path: '',
    component: InicioComponent,
    children: [
      {
        path: 'shop',
        data: { key: 'shop' },
        loadChildren: "./modules/shop.module#ShopModule",
        pathMatch: 'full'
      },
      {
        path: 'car/:id',
        data: { key: 'car' },
        loadChildren: "./modules/car.module#CarModule",
        pathMatch: 'full'
      },
      {
        // This one has child routes, which I will add if needed
        path: 'workOrder',
        data: { key: 'workOrder' },
        loadChildren: "./modules/workOrder.module#WorkOrderModule",
      }
      // And many more
    ]
  }
]

如果您的延迟加载模块配置正确,应该可以正常工作。 希望对你有所帮助,来自智利的问候