angular-material-19

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

When to Use

适用场景

  • Using Angular Material 19 components
  • Creating custom form controls with signal-based patterns
  • Implementing Material 3 theming with CSS variables
  • Setting up dark/light mode switching
  • Using CDK features (2D Drag & Drop, Overlay, A11y)
  • Working with the new timepicker component
Reference files (loaded on demand):
  • timepicker.md — Timepicker usage, intervals, validation
  • theming.md — M3 theming, dark mode, override mixins, theme service
  • cdk-patterns.md — 2D drag-drop, tab reorder, overlay, selection
  • custom-controls.md — ControlValueAccessor, MatFormFieldControl with signals

  • 使用Angular Material 19组件
  • 基于信号模式创建自定义表单控件
  • 使用CSS变量实现Material 3主题配置
  • 设置深色/浅色模式切换
  • 使用CDK功能(2D拖放、浮层、无障碍访问)
  • 使用新增的时间选择器组件
参考文件(按需加载):
  • timepicker.md — 时间选择器用法、时间间隔、验证
  • theming.md — M3主题配置、深色模式、覆盖混合宏、主题服务
  • cdk-patterns.md — 2D拖放、标签页重排、浮层、选择功能
  • custom-controls.md — ControlValueAccessor、基于信号的MatFormFieldControl

Angular Material 19 Key Changes

Angular Material 19 主要变更

Material 3 (M3) is Stable

Material 3(M3)已稳定

Material 3 is now the default design system. Key features:
  • Design tokens as CSS variables — All styling via
    --mat-*
    variables
  • light-dark()
    function
    — Native CSS for theme switching
  • Component override mixins — Granular customization without specificity wars
  • New "Styling" tab — Each component's docs now shows override API
Material 3现已成为默认设计系统。主要特性:
  • 作为CSS变量的设计令牌 — 所有样式通过
    --mat-*
    变量实现
  • light-dark()
    函数
    — 原生CSS实现主题切换
  • 组件覆盖混合宏 — 精细化定制,避免优先级冲突
  • 新增「样式」标签页 — 每个组件的文档现在展示覆盖API

New Components in v19

v19中的新增组件

  • Timepicker (
    mat-timepicker
    ) — Native time selection → see timepicker.md
  • 2D Drag & Drop — Mixed orientation support in CDK → see cdk-patterns.md
  • Tab reordering — Draggable tabs with CDK

  • 时间选择器
    mat-timepicker
    ) — 原生时间选择 → 查看timepicker.md
  • 2D拖放 — CDK支持混合方向 → 查看cdk-patterns.md
  • 标签页重排 — 基于CDK的可拖拽标签页

Quick Reference: Common Imports

快速参考:常用导入

typescript
// Forms
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatTimepickerModule } from '@angular/material/timepicker'; // NEW v19
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';

// Buttons & Icons
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';

// Layout
import { MatCardModule } from '@angular/material/card';
import { MatTabsModule } from '@angular/material/tabs';
import { MatExpansionModule } from '@angular/material/expansion';

// Data Display
import { MatTableModule } from '@angular/material/table';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatSortModule } from '@angular/material/sort';
import { MatChipsModule } from '@angular/material/chips';
import { MatTooltipModule } from '@angular/material/tooltip';

// Feedback
import { MatDialogModule } from '@angular/material/dialog';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';

// CDK
import { DragDropModule } from '@angular/cdk/drag-drop';
import { OverlayModule } from '@angular/cdk/overlay';

typescript
// Forms
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatTimepickerModule } from '@angular/material/timepicker'; // NEW v19
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';

// Buttons & Icons
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';

// Layout
import { MatCardModule } from '@angular/material/card';
import { MatTabsModule } from '@angular/material/tabs';
import { MatExpansionModule } from '@angular/material/expansion';

// Data Display
import { MatTableModule } from '@angular/material/table';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatSortModule } from '@angular/material/sort';
import { MatChipsModule } from '@angular/material/chips';
import { MatTooltipModule } from '@angular/material/tooltip';

// Feedback
import { MatDialogModule } from '@angular/material/dialog';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';

// CDK
import { DragDropModule } from '@angular/cdk/drag-drop';
import { OverlayModule } from '@angular/cdk/overlay';

Material Dialog Pattern

Material 对话框模式

typescript
import { Component, inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule } from '@angular/material/dialog';
import { MatButtonModule } from '@angular/material/button';

@Component({
    selector: 'confirm-dialog',
    imports: [MatDialogModule, MatButtonModule],
    template: `
        <h2 mat-dialog-title>{{ data.title }}</h2>
        <mat-dialog-content>
            <p>{{ data.message }}</p>
        </mat-dialog-content>
        <mat-dialog-actions align="end">
            <button mat-button mat-dialog-close>Cancel</button>
            <button mat-flat-button color="warn" [mat-dialog-close]="true">
                {{ data.confirmText ?? 'Confirm' }}
            </button>
        </mat-dialog-actions>
    `,
})
export class ConfirmDialogComponent
{
    readonly data = inject<{ title: string; message: string; confirmText?: string }>(MAT_DIALOG_DATA);
}

typescript
import { Component, inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule } from '@angular/material/dialog';
import { MatButtonModule } from '@angular/material/button';

@Component({
    selector: 'confirm-dialog',
    imports: [MatDialogModule, MatButtonModule],
    template: `
        <h2 mat-dialog-title>{{ data.title }}</h2>
        <mat-dialog-content>
            <p>{{ data.message }}</p>
        </mat-dialog-content>
        <mat-dialog-actions align="end">
            <button mat-button mat-dialog-close>Cancel</button>
            <button mat-flat-button color="warn" [mat-dialog-close]="true">
                {{ data.confirmText ?? 'Confirm' }}
            </button>
        </mat-dialog-actions>
    `,
})
export class ConfirmDialogComponent
{
    readonly data = inject<{ title: string; message: string; confirmText?: string }>(MAT_DIALOG_DATA);
}

Material Table with Signals

基于信号的Material表格

typescript
import { Component, signal, computed, viewChild } from '@angular/core';
import { MatTableModule } from '@angular/material/table';
import { MatSortModule, MatSort, Sort } from '@angular/material/sort';
import { MatPaginatorModule, MatPaginator, PageEvent } from '@angular/material/paginator';

@Component({
    selector: 'app-data-table',
    imports: [MatTableModule, MatSortModule, MatPaginatorModule],
    template: `
        <table [dataSource]="dataSource()" mat-table matSort
               (matSortChange)="onSortChange($event)">
            <!-- columns -->
            <tr *matHeaderRowDef="displayedColumns" mat-header-row></tr>
            <tr *matRowDef="let row; columns: displayedColumns" mat-row></tr>
        </table>
        <mat-paginator [length]="totalItems()" [pageSize]="pageSize()"
                       [pageSizeOptions]="[10, 25, 50]"
                       (page)="onPageChange($event)"></mat-paginator>
    `,
})
export class DataTableComponent {
    data = signal<any[]>([]);
    totalItems = signal(0);
    pageSize = signal(10);
    sort = viewChild(MatSort);
    paginator = viewChild(MatPaginator);
    displayedColumns = ['name', 'email', 'actions'];
    dataSource = computed(() => this.data());

    onSortChange(sort: Sort): void { /* update & reload */ }
    onPageChange(event: PageEvent): void { /* update & reload */ }
}

typescript
import { Component, signal, computed, viewChild } from '@angular/core';
import { MatTableModule } from '@angular/material/table';
import { MatSortModule, MatSort, Sort } from '@angular/material/sort';
import { MatPaginatorModule, MatPaginator, PageEvent } from '@angular/material/paginator';

@Component({
    selector: 'app-data-table',
    imports: [MatTableModule, MatSortModule, MatPaginatorModule],
    template: `
        <table [dataSource]="dataSource()" mat-table matSort
               (matSortChange)="onSortChange($event)">
            <!-- columns -->
            <tr *matHeaderRowDef="displayedColumns" mat-header-row></tr>
            <tr *matRowDef="let row; columns: displayedColumns" mat-row></tr>
        </table>
        <mat-paginator [length]="totalItems()" [pageSize]="pageSize()"
                       [pageSizeOptions]="[10, 25, 50]"
                       (page)="onPageChange($event)"></mat-paginator>
    `,
})
export class DataTableComponent {
    data = signal<any[]>([]);
    totalItems = signal(0);
    pageSize = signal(10);
    sort = viewChild(MatSort);
    paginator = viewChild(MatPaginator);
    displayedColumns = ['name', 'email', 'actions'];
    dataSource = computed(() => this.data());

    onSortChange(sort: Sort): void { /* update & reload */ }
    onPageChange(event: PageEvent): void { /* update & reload */ }
}

Anti-Patterns

反模式

AvoidDo Instead
@ViewChild(MatSort)
decorator
viewChild(MatSort)
signal query
Manual
stateChanges.next()
calls everywhere
Use
effect()
to auto-emit on signal changes
Importing entire Material moduleImport only needed component modules
Using
any
for dialog data
Create typed interfaces
Hardcoded colors in componentsUse
--mat-sys-*
CSS variables
@media (prefers-color-scheme)
manually
Use
light-dark()
function in theme
Custom dark mode class logicSet
color-scheme: light dark
on html
Using third-party timepickerUse native
mat-timepicker
(v19+)

避免做法推荐做法
@ViewChild(MatSort)
装饰器
viewChild(MatSort)
信号查询
在各处手动调用
stateChanges.next()
使用
effect()
在信号变化时自动触发
导入完整的Material模块仅导入所需的组件模块
对对话框数据使用
any
类型
创建类型化接口
在组件中硬编码颜色使用
--mat-sys-*
CSS变量
手动使用
@media (prefers-color-scheme)
在主题中使用
light-dark()
函数
自定义深色模式类逻辑在html上设置
color-scheme: light dark
使用第三方时间选择器使用原生
mat-timepicker
(v19+)

Migration Checklist

迁移检查清单

  • Replace third-party timepicker with
    mat-timepicker
  • Convert
    @ViewChild
    queries to signal queries
  • Update theming to use M3
    mat.theme()
    mixin
  • Implement dark mode with
    light-dark()
    function
  • Use component override mixins instead of deep CSS selectors
  • Convert custom controls to use signals internally

  • mat-timepicker
    替换第三方时间选择器
  • @ViewChild
    查询转换为信号查询
  • 更新主题配置以使用M3
    mat.theme()
    混合宏
  • 使用
    light-dark()
    函数实现深色模式
  • 使用组件覆盖混合宏替代深层CSS选择器
  • 将自定义控件转换为内部使用信号的实现

Related Skills

相关技能

SkillWhen to Use Together
angular-19
Angular 19 patterns, signals, resource API
tailwind
Combined Tailwind + Material styling
typescript
TypeScript patterns for typed components

技能名称协同使用场景
angular-19
Angular 19模式、信号、资源API
tailwind
Tailwind + Material 组合样式
typescript
用于类型化组件的TypeScript模式

Resources

资源