如何在Angular 4中通过共享模块正确导入Angular Material模块?

12

我正在使用Angular和Angular Material构建一个应用程序,但我的模块结构存在一些问题。

根据指南的建议,导入MaterialModule已经被弃用,不应再这样做,因此我制作了一个单独的MaterialModule,在其中仅导入我需要使用的Material模块;然后在SharedModule中导入此模块,最终在所有需要它的地方导入,包括主AppModule。

我正在使用的其中一个Material组件是MdTooltip,一切都正常工作,除了当我在平板电脑上测试应用程序时:发生的情况是工具提示不会像应该的那样对长时间点击做出反应,也不会打开。我设法让它正常工作的唯一方法是在我的AppModule中导入完整的MaterialModule(来自@angular/material),这非常错误和不优雅。任何其他方法似乎都无法解决这个问题,而且还会带来新的问题。

这些是我的模块(去掉了多余的导入语句):

MaterialModule:

import { NgModule } from '@angular/core';
import {...} from '@angular/material';

@NgModule({
  imports: [
    MdGridListModule,
    MdButtonModule,
    MdTabsModule,
    MdToolbarModule,
    MdCardModule,
    MdInputModule,
    MdSelectModule,
    MdAutocompleteModule,
    MdIconModule,
    MdTooltipModule
  ],
  exports: [
    MdGridListModule,
    MdButtonModule,
    MdTabsModule,
    MdToolbarModule,
    MdCardModule,
    MdInputModule,
    MdSelectModule,
    MdAutocompleteModule,
    MdIconModule,
    MdTooltipModule
  ],
  providers: [
    MdIconRegistry
  ]
})

export class MaterialModule {}

共享模块:

import { MaterialModule } from '../material/app-material.module';
@NgModule({
  imports:      [
    CommonModule,
    MaterialModule,
    FlexLayoutModule,
    FormsModule,
    ReactiveFormsModule
  ],
  declarations: [
    NavbarComponent,
    SearchFiltersComponent,
    RightCurrencyPipe
  ],
  exports:      [
    CommonModule,
    FormsModule,
    ReactiveFormsModule,
    MaterialModule,
    FlexLayoutModule,
    NavbarComponent,
    RightCurrencyPipe,
    SearchFiltersComponent
  ],
  providers: [
    SpinnerService,
    ProductsService,
    StatePersistenceService
  ]
})

export class SharedModule {}

应用模块:

import { MaterialModule } from "@angular/material";
@NgModule({
  declarations: [
    AppComponent,
    ProductPageComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    RouterModule,
    BrowserAnimationsModule,
    AppRoutingModule,
    SharedModule,
    CoreModule,
    LoginModule,
    MaterialModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

我是否做错了什么?你会如何将你的应用程序划分为子模块?

先行感谢。


2
我做了和你一样的事情,但是我收到了“StaticInjectorError [ElementRef]:”错误,所有的东西都已经加载完毕,但是Angular Material组件无法工作。你有什么想法为什么会出现这种情况吗? - molikh
4个回答

2

你的方法很好。你提出的结构是material.angular.io中提出的一种替代方案。我不确定为什么你的工具提示不起作用。但我想建议你只在根模块上使用自定义MaterialModule一次。没有必要再在SharedModule中导入它。


2
根据您的编译和部署策略,您需要使用树摇(用于死代码消除或活代码导入)。这是MaterialModule被弃用的主要原因。官方建议在需要使用它的模块中仅导入所需组件。您创建一个包含所有导入内容的单个MaterialModule的解决方案会撤销该方面,但根据您的项目结构可能有效(例如,如果您仅使用单个模块)。
尝试从您的SharedModule导出中删除MaterialModule。这样,您的应用程序根目录中只有一个入口点。

那是一个深入的回答,但有些东西我在原始问题中没有理解。SharedModule声明和导出的组件广泛使用Material组件,这使得导入我的MaterialModule(或单个组件)成为必要;然而,工具提示并不能正常工作。让它正常工作的方法是在我的AppModule中导入已弃用的MaterialModule,同时保留我的自定义MaterialModule在SharedModule中导入。为什么我需要在根部导入完整的MaterialModule?这就是困扰我的地方。 - Samuele
你可能想要检查node_modules中安装的版本:已弃用的MaterialModule在最新版本中不应该做任何事情。我可以看到你在SharedModule中有两个组件,在AppModule中有两个组件(建议将它们放在自己的模块中)。如果你没有从SharedModule导出并且只在AppModule中导入需要用于其组件(AppComponent, ProductPageComponent)的特定组件,会怎样呢? - Raven
你说得对,被弃用的MaterialModule基本上什么都不做,只是一个空类。我尝试在每个模块中导入我需要的所有单独模块,除了工具提示的触摸功能之外,一切正常运作。 由于某种原因,唯一能让它工作的方法是在我的主要AppModule中导入被弃用的MaterialModule,无论我做什么其他操作。如果我导入它,就会获得触摸功能,如果我不导入它,就无法工作。这对我来说没有太多意义,老实说,可能与hammer.js和BrowserModule的导入位置有关吗? - Samuele

1

你的第一个错误是在 SharedModule 中使用服务。SharedModule 不应该有 Providers 数组。CoreModule 用于服务。

你不需要在 shared module 中导入所有的东西。SharedModule 通常用于导出。另外,MaterialModule 不需要导入,因为它不使用它们。它的目的是导出。

如果 NavBarComponent 在整个应用程序中都被使用,那么它应该在 CoreModule 中。而不是在 SharedModule 中。

如果没有必要,不要将 SharedModule 导入到 AppModule 中。SharedModule 是用于 FeaturedModules 的。

阅读官方文档:https://angular.io/guide/ngmodule-faq#what-kinds-of-modules-should-i-have-and-how-should-i-use-them


而为什么SharedModule不应该有任何提供者呢?如果我想为每个功能添加一个新的服务,那有什么问题吗? - CornelC
如果您有一个特定于功能的服务,应将其放在该功能模块中,而不是共享模块中。共享模块适用于所有内容。 - LacOniC
能否解释一下你的陈述? - CornelC

0
  1. 在 "src\app" 中使用以下命令创建一个共享模块:ng g module shared

  2. 在共享模块中导入所有需要的材料模块。重要提示!!!有时,如果您尝试一次性导入一组模块,则会出现错误。您应该像下面这样逐个导入它们=>

    import { MatButtonModule } from '@angular/material/button';

    import {MatFormFieldModule} from '@angular/material/form-field';

    import {MatInputModule} from '@angular/material/input';

然后

    @NgModule({
  declarations: [],
  imports: [
    CommonModule,
    MatButtonModule,
    MatFormFieldModule,
    MatInputModule
  ],
  exports: [
    MatButtonModule,
    MatFormFieldModule,
    MatInputModule

  ]
})

现在,您可以在需要导入共享模块的任何地方导入此共享模块中导入的一个或多个材料模块。 例如,如果您需要在学生示例中使用Angular Material =>

import {SharedModule} from '../shared/shared.module'

然后

@NgModule({
  declarations: [
    TdFormComponent],
  imports: [
    CommonModule,
    SharedModule,
    
  ]
})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接