Angular 14升级15后Material Legacy表单主题失效问题排查
升级Angular 14到15后Angular Material Legacy组件出现mat-mdc类及显示异常问题
将Angular从14升级到15后,使用Angular Material的Legacy版本模块,但出现字体与表单显示异常。检查发现HTML中出现了Legacy版本不应有的mat-mdc类,无法定位代码或配置中的具体错误,求排查原因。
Legacy模块导入代码
import { NgModule } from '@angular/core'; import { MatLegacyTabsModule as MatTabsModule } from '@angular/material/legacy-tabs'; import { MatLegacyButtonModule as MatButtonModule } from '@angular/material/legacy-button'; import { MatLegacyProgressSpinnerModule as MatProgressSpinnerModule } from '@angular/material/legacy-progress-spinner'; import { MatLegacyTooltipModule as MatTooltipModule } from '@angular/material/legacy-tooltip'; import { MatLegacySelectModule as MatSelectModule } from '@angular/material/legacy-select'; import { MatLegacySlideToggleModule as MatSlideToggleModule } from '@angular/material/legacy-slide-toggle'; import { MatLegacyInputModule as MatInputModule } from '@angular/material/legacy-input'; import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatLegacySnackBarModule as MatSnackBarModule} from '@angular/material/legacy-snack-bar'; import { MatLegacyRadioModule as MatRadioModule } from '@angular/material/legacy-radio'; import { MatStepperModule } from '@angular/material/stepper'; import { MatLegacyFormFieldModule as MatFormFieldModule } from '@angular/material/legacy-form-field'; import { MatLegacyMenuModule as MatMenuModule } from '@angular/material/legacy-menu'; import { MatDividerModule } from '@angular/material/divider'; import { MatGridListModule } from '@angular/material/grid-list'; import { MatToolbarModule } from '@angular/material/toolbar'; import { MatIconModule } from '@angular/material/icon'; import { MAT_LEGACY_DIALOG_DEFAULT_OPTIONS, MatLegacyDialogModule as MatDialogModule } from '@angular/material/legacy-dialog'; import { MatLegacyAutocompleteModule as MatAutocompleteModule } from '@angular/material/legacy-autocomplete'; import { MatExpansionModule } from '@angular/material/expansion'; import { MatLegacyCardModule as MatCardModule } from '@angular/material/legacy-card'; import { FormlyMaterialModule } from '@ngx-formly/material'; import { MatLegacyTableModule as MatTableModule } from '@angular/material/legacy-table'; import { MatBadgeModule } from '@angular/material/badge'; import { MatLegacyPaginatorModule as MatPaginatorModule } from '@angular/material/legacy-paginator'; import { MatSortModule } from '@angular/material/sort'; import { MatLegacyChipsModule as MatChipsModule } from '@angular/material/legacy-chips'; import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { MatLegacyProgressBarModule as MatProgressBarModule } from '@angular/material/legacy-progress-bar'; import { MatLegacySliderModule as MatSliderModule } from '@angular/material/legacy-slider'; import { MatLegacyCheckboxModule as MatCheckboxModule } from '@angular/material/legacy-checkbox'; import { MomentDateAdapter } from '@angular/material-moment-adapter'; import { LegacyDateAdapter as DateAdapter, MAT_LEGACY_DATE_FORMATS, MAT_LEGACY_DATE_LOCALE } from '@angular/material/legacy-core'; import { MultipleType } from '@Shared/enums/config.enum'; const format = { parse: { dateInput: 'DD/MM/YYYY' }, display: { dateInput: 'DD/MM/YYYY', monthYearLabel: 'MMMM YYYY', dateA11yLabel: 'MM/DD/YYYY', monthYearA11yLabel: 'MMMM YYYY' } }; const modules = [ MatTabsModule, MatSelectModule, MatSlideToggleModule, MatDatepickerModule, MatButtonModule, MatInputModule, MatSnackBarModule, MatProgressSpinnerModule, MatTooltipModule, MatRadioModule, MatStepperModule, MatFormFieldModule, MatMenuModule, MatDividerModule, MatGridListModule, MatToolbarModule, MatIconModule, MatAutocompleteModule, MatDialogModule, MatAutocompleteModule, MatExpansionModule, MatCardModule, FormlyMaterialModule, MatTableModule, MatPaginatorModule, MatBadgeModule, MatSortModule, MatChipsModule, MatButtonToggleModule, MatProgressBarModule, MatSliderModule, MatCheckboxModule ]; @NgModule({ imports: [ ...modules ], exports: [ ...modules, ], providers: [ { provide: MAT_LEGACY_DIALOG_DEFAULT_OPTIONS, useValue: {hasBackdrop: false} }, { provide: MAT_LEGACY_DATE_LOCALE, useValue: 'fr' }, { provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_LEGACY_DATE_LOCALE] }, { provide: MAT_LEGACY_DATE_FORMATS, useValue: format } ] }) export class MaterialModule { constructor(private readonly adapter: DateAdapter<MultipleType>) {} french() { this.adapter.setLocale('fr'); } }
style.scss代码
@use '@angular/material' as mat; @include mat.legacy-core(); $md-test-blue: (50 : #e8eafe, 100 : #c5cbfe, 200 : #9fa9fd, 300 : #7987fc, 400 : #5c6dfb, 500 : #3f53fa, 600 : #394cf9, 700 : #3142f9, 800 : #2939f8, 900 : #1b29f6, A100 : #ffffff, A200 : #f6f7ff, A400 : #c3c7ff, A700 : #aaaeff, contrast: (50 : #000000, 100 : #000000, 200 : #000000, 300 : #000000, 400 : #ffffff, 500 : #ffffff, 600 : #ffffff, 700 : #ffffff, 800 : #ffffff, 900 : #ffffff, A100 : #000000, A200 : #000000, A400 : #000000, A700 : #000000) ); $md-test-red: (50 : #fde5e9, 100 : #fbbdc8, 200 : #f891a4, 300 : #f56580, 400 : #f34464, 500 : #f12349, 600 : #ef1f42, 700 : #ed1a39, 800 : #eb1531, 900 : #e70c21, A100 : #ffffff, A200 : #ffdee0, A400 : #ffabb1, A700 : #ff9199, contrast: (50 : #000000, 100 : #000000, 200 : #000000, 300 : #000000, 400 : #ffffff, 500 : #ffffff, 600 : #ffffff, 700 : #ffffff, 800 : #ffffff, 900 : #ffffff, A100 : #000000, A200 : #000000, A400 : #000000, A700 : #000000) ); @import "./mixins.scss"; html, body { height: 100%; width: 100%; } body { margin: 0; } html { font-size: 14px; } :root { --primary-color: #F12349; --accent-color: #3F53FA; --nav-color1: rgba(0,0,0,.87); --nav-color2: rgba(0,0,0,0.5); --white-background: #ffffff; --input-border-style: solid; --input-border-width: 1px; --input-border-untouched-color: #868898; --input-border-touched-color: #5264FA; --input-border-invalid-color: red; --input-border-radius: 4px; --input-box-shadow: 0 2px 3px 0 rgba(73,86,92,0.12), 0 0 4px 0 rgba(73,86,92,0.1); } $test-font-family: "'sofia-pro', sans-serif"; $typography-levels: mat.define-legacy-typography-config( $font-family: "'sofia-pro', sans-serif" ); $typography: mat.define-legacy-typography-config($test-font-family); $test-primary: mat.define-palette($md-test-blue); $test-accent: mat.define-palette($md-test-red); $theme: mat.define-light-theme(( color: ( primary: $rexmat-primary, accent: $rexmat-accent ), typography: mat.define-legacy-typography-config( $font-family: "'sofia-pro', sans-serif"), )); @include mat.all-legacy-component-themes($theme); @import './test-theme.scss'; /* You can add global styles to this file, and also import other style files */
angular.json样式配置
"styles": [ "./node_modules/@angular/material/legacy-prebuilt-themes/legacy-indigo-pink.css", "src/styles.scss" ],
排查关键点
非Legacy模块混入:
代码中MatDatepickerModule、MatStepperModule、MatDividerModule等多个模块未使用Legacy版本,Angular 15中这些模块默认是MDC实现,会生成mat-mdc类,和Legacy组件样式冲突。需替换为对应Legacy模块,比如MatLegacyDatepickerModule、MatLegacyStepperModule。Formly模块依赖冲突:
使用的FormlyMaterialModule默认依赖MDC版本组件,会输出mat-mdc类。需替换为@ngx-formly/material-legacy模块,确保Formly适配Legacy组件。主题配置错误:
$theme定义中使用了未声明的$rexmat-primary和$rexmat-accent,应改为$test-primary和$test-accent,否则主题配置无效导致样式异常。- 同时引入预构建Legacy主题和自定义主题,存在优先级冲突,建议移除
legacy-indigo-pink.css的引用,仅保留自定义主题。
清理构建缓存:
升级后可能残留旧缓存,执行ng clean后重新构建项目,确保加载最新模块和样式。
内容的提问来源于stack exchange,提问作者testyahoo
相关产品推荐
相关产品推荐

