掌握了基本的 Angular 知识之后,现在让我们写一些真正的 Angular 代码吧。本文介绍使用 Angular 构建前端工程的时候使用 Angular Material 组件库的相关知识。
1. Angular Material 组件库
- 使用 nvm 安装 node@16.14.2
- 在 node@16.14.2 环境下安装 14.x 版本的 angular 脚手架
npm install -g @angular/cli@14
- 创建一个新项目
ng new demo && cd demo
- 安装组件库:
ng add @angular/material@13.0.0
并确保在控制台上看到如下所示的信息: - 启动:
yarn start
- 按照下图所示在 app.module.ts 中引入 material 提供的 button module. 注意其在 imports 中的顺序排在最后。
- 删除 app.component.html 中的所有代码,然后输入以下内容。注意这里和 react 不一样,不需要遵守单一根标签的规则。
- 上面就是在 Angular 项目中引入 Matrial 库的过程了。
2. 制作一个名为 Matrial 的 shared module
- 首先,创建一个名为 material 的子组件
ng g m material
- 然后将其中的代码修改成如下形式:
ts
import { NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
const MaterialComponents = [
MatButtonModule,
]
@NgModule({
imports: [MaterialComponents],
exports:[MaterialComponents]
})
export class MaterialModule { }
- 最后将 app.module.ts 中关于 material 相关的引入换成对刚才新建的 MaterialModule 的引入。修改之后的代码如下所示。
ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MaterialModule } from './material/material.module';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
MaterialModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
- 上述做法并不是多此一举,而是为了保证 app.module.ts 的干净整洁。
3. Material 中的 Typography
与此相关的概念是 typographic level. 体现在 class 上面,类似于 TailwindCSS, 通过一些预制的类名来修改文字的样式。Typography 是 Angular Material 的排版样式。这些样式通常用于设置文本的大小、行距和字体权重等。常见的如下所示:
html
<div class="mat-display-4">This is display 4</div>
<div class="mat-display-3">This is display 3</div>
<div class="mat-display-2">This is display 2</div>
<div class="mat-display-1">This is display 1</div>
<div class="mat-headline">This is a heading for h1</div>
<div class="mat-title">This is a heading for h2</div>
<div class="mat-subheading-2">This is a heading for h3</div>
<div class="mat-subheading-1">This is a heading for h4</div>
<div class="mat-body-1">This is body text</div>
<div class="mat-body-2">This is bold body text</div>
<div class="mat-caption">This is caption text</div>
效果如下所示:
3.1 mat-typography 类
在Angular Material框架中,mat-typography
类名是一个特殊的类,它用于自动应用一系列预定义的排版样式到HTML元素。当你在一个祖先元素上添加 mat-typography
类时,它会改变该元素内部的一些标准HTML标签(如h1
, h2
, p
等)的样式,使它们符合Material Design的排版规范。
具体来说,mat-typography
类会与Angular Material的排版CSS样式一起工作,自动调整以下元素的样式:
- 标题元素 (
h1
,h2
,h3
,h4
,h5
,h6
) - 段落 (
p
) - 列表 (
ul
,ol
,li
) - 强调文本 (
strong
,b
) - 以及其他一些文本相关元素
这个类使得开发者可以很方便地将Material Design的排版风格应用到整个页面或者页面的某个部分,而无需单独为每个元素指定样式。要使用 mat-typography
,你需要在你的Angular项目中包含Angular Material的排版CSS文件,并将 mat-typography
类添加到想要应用Material Design排版的元素上。
例如,如果你想让整个页面都采用Material Design的排版,你可以在<body>
标签上添加这个类:
html
<body class="mat-typography">
<!-- 页面内容 -->
</body>
或者,如果你只想对页面的某个部分应用这种排版,你可以将该类添加到某个具体的<div>
上:
html
<div class="mat-typography">
<!-- 部分页面内容 -->
</div>
为了使 mat-typography
类生效,你的项目需要正确引入Angular Material的CSS文件,并且你的Angular项目应该已经安装了Angular Material库。
4. Button
下图展示的是 Angular 中所有的 button 类型:
Attribute | Description |
---|---|
mat-button |
Rectangular text button w/ no elevation |
mat-raised-button |
Rectangular contained button w/ elevation |
mat-flat-button |
Rectangular contained button w/ no elevation |
mat-stroked-button |
Rectangular outlined button w/ no elevation |
mat-icon-button |
Circular button with a transparent background, meant to contain an icon |
mat-fab |
Circular button w/ elevation, defaults to theme's accent color |
mat-mini-fab |
Same as mat-fab but smaller |
5. button-toggle
具有状态的 button 组件。
html
<div class="toggle-button">
<mat-button-toggle #toggle checked>
{{ toggle.checked }}
</mat-button-toggle>
</div>
或者
html
<div class="toggle-button">
<mat-button-toggle #toggle disabled checked="false">
{{ toggle.checked }}
</mat-button-toggle>
</div>
上述代码中的 #toggle
有点像 react 中的 ref, 可以拿到绑定标签上面的状态。而 checked 则表示初始的默认状态为选中。你还可以使用 disabled 置灰按钮或者使用 disableRipple 来禁用默认的水波纹效果。
效果如下所示:
mat-button-toggle-group: 用来将 toggle button 组织起来的组。这是因为,显而易见的是 toggle button 可以实现 radio 或者 checkbox 的功能。
html
<div class="toggle-button">
<mat-button-toggle-group #toggleGroup="matButtonToggleGroup">
<mat-button-toggle value="angualr">angular</mat-button-toggle>
<mat-button-toggle value="react">react</mat-button-toggle>
<mat-button-toggle value="vue">vue</mat-button-toggle>
</mat-button-toggle-group>
{{ toggleGroup.value }}
</div>
效果如下所示:
而在此基础之上实现多选是相当容易的,只需要在 group 标签上加上 multiple 即可。
<mat-button-toggle-group #toggleGroup="matButtonToggleGroup" multiple>
toggleGroup 相当于是 html 自用的变量,可以通过调用组件函数的方式将其值传递给组件,然后广播出去:
html
<div class="toggle-button">
<mat-button-toggle-group
multiple
#toggleGroup="matButtonToggleGroup"
(change)="onToggleChange(toggleGroup.value)"
>
<mat-button-toggle value="angular">Angular</mat-button-toggle>
<mat-button-toggle value="react">React</mat-button-toggle>
<mat-button-toggle value="vue">Vue</mat-button-toggle>
</mat-button-toggle-group>
</div>
在组件中接受然后广播出去:
ts
import { Component, EventEmitter, Output } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
@Output() toggleValueChanged = new EventEmitter<string>();
title = 'demo';
onToggleChange(value: string) {
console.log('value--', value);
this.toggleValueChanged.emit(value);
}
}
6. Icons
使用 Material 的 Icon 模块。首当其冲的当然是要在我们的 MaterialModule 中引入然后将相应的模块暴露出去,这个模块就是 MatIconModule: import { MatIconModule } from '@angular/material/icon';
html
<mat-icon
aria-hidden="false"
aria-label="Example home icon"
fontIcon="home"
color="primary"
></mat-icon>
<mat-icon matBadge="15" matBadgeColor="warn">home</mat-icon>
Badge
我们可以通过在 mat-icon 或者 button 或者 span 等其它标签上添加 matBadge="15" matBadgeColor="warn"
的方式设置 badge 的颜色和数字。也可以通过 matBadgePosition="below before"
设置 badge 出现的位置。通过 matBadgeSize="small"
设置 badge 的大小。
关于 color 可以设置的值有:export declare type ThemePalette = 'primary' | 'accent' | 'warn' | undefined;
下面这个实例实现了当 badge 的值小于 5 隐藏,大于等于 5 的时候显示的效果:
html
<mat-icon
[matBadge]="badgeCount"
(click)="(handleClick)"
matBadgeColor="primary"
matBadgePosition="below after"
matBadgeSize="small"
>
ts
badgeCount = 1;
handleClick() {
this.badgeCount += 1;
}
需要注意的是 matBadge 中不知可以写数字,还可以写任何文本。
7. Progress Spinner
对应的 module 的名称是 MatProgressSpinnerModule
, 在使用之前记得引入这个模块。
使用 mat-spinner 做一个点击加载数据的时候出现 spin 等待的效果:
html
<div class="container">
<mat-spinner *ngIf="showSpin" color="accent" diameter="50"></mat-spinner>
<mat-icon [matBadge]="badgeCount" matBadgeColor="warn" (click)="handleClick()"
>home</mat-icon
>
<!-- <mat-progress-spinner value="34"></mat-progress-spinner> -->
</div>
ts
import { Component, EventEmitter, Output } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
@Output() toggleValueChanged = new EventEmitter<string>();
title = 'demo';
badgeCount = 1;
showSpin = false;
loadData() {
this.showSpin = true;
setTimeout(() => { this.showSpin = false; this.badgeCount += 1; }, 1000)
}
handleClick() {
this.loadData();
}
// onToggleChange(value: string) {
// console.log('value--')
// this.toggleValueChanged.emit(value);
// }
}
效果如下所示:
8. NavBar
相关的 module 名叫 MatToolbarModule
, 记得在使用之前引用。
css
.nav-bar {
display: flex;
justify-content: space-between;
}
span {
margin-left: 20px;
}
html
<mat-toolbar color="primary" class="nav-bar">
<div>Codevolution</div>
<div>
<span>Home</span>
<span>About</span>
<span>Help</span>
</div>
</mat-toolbar>
效果嘎嘎好:
9. Sidenav
相关的 module 名叫 MatSidenavModule
, 记得在使用之前引用。
下面的代码完成了一个展开或者收起侧边栏的功能:
html
<mat-drawer-container class="example-container">
<mat-drawer mode="side" [opened]="showSpin">Drawer content</mat-drawer>
<mat-drawer-content
>Main content
<mat-button-toggle
#toggle
checked="false"
color="primary"
(change)="handleChange(toggle.checked)"
>{{ toggle.checked ? "收起" : "展开" }}</mat-button-toggle
>
</mat-drawer-content>
</mat-drawer-container>
你可以通过 mode 属性设置 sidenav 的特性,这个值默认为 over. 也可以取值:export declare type MatDrawerMode = 'over' | 'push' | 'side';
这个属性设置的本质山是 drawer 和 content 之间的相互关系。
可以给 mat-sidenav 上面设置 ref 然后使用这个 ref 上的方法控制侧边栏的打开或者关闭状态:
html
<mat-drawer-container class="example-container">
<mat-drawer #myBar mode="side" [opened]="showSpin">Drawer content</mat-drawer>
<mat-drawer-content
>Main content
<mat-button-toggle
#toggle
checked="false"
color="primary"
(change)="handleChange(toggle.checked)"
>{{ toggle.checked ? "收起" : "展开" }}</mat-button-toggle
>
<button (click)="myBar.open()">open</button>
<button (click)="myBar.close()">close</button>
<button (click)="myBar.toggle()">toggle</button>
</mat-drawer-content>
</mat-drawer-container>
通过使用 ref 我们的 html 模板拥有了一定的自治权。
除此之外,这个组件在侧边栏打开或者关上的时候都会触发名为 opened 的事件,因此我们可以监听这个事件,将侧边栏的状态信息传递出去:(opened)="handleOpen(true)" (close)="handleOpen(false)"
10. Menus
相关的 module 名叫 MatMenuModule
, 记得在使用之前引用。
menu 一般是绑定在一个 button 上面,当这个 button 点击的时候会弹出来。如果不是这样使用的,则不会被渲染出来。
html
<mat-menu #appMenu="matMenu">
<button mat-menu-item>Front-end</button>
<button mat-menu-item>Back-end</button>
</mat-menu>
<button mat-flat-button [mat-menu-trigger-for]="appMenu">Menu</button>
效果如下所示:
还可以使用下面的方式生成多级菜单:
html
<mat-menu #appMenu="matMenu" xPosition="after" yPosition="above">
<button mat-menu-item [mat-menu-trigger-for]="subMenu">Front-end</button>
<button mat-menu-item>Back-end</button>
</mat-menu>
<button mat-flat-button [mat-menu-trigger-for]="appMenu">Menu</button>
<mat-menu #subMenu="matMenu">
<button mat-menu-item>Angular</button>
<button mat-menu-item>React</button>
<button mat-menu-item>Vue</button>
</mat-menu>
需要注意的有两点:一个是 mat-menu-trigger-for 的绑定;一个是代码组织结构不等于 dom 的组织结构。实际上在上面的代码中,最外层的就是 button, 菜单项是 button 的子节点。
更好看的菜单项:
html
<button
mat-icon-button
[matMenuTriggerFor]="menu"
aria-label="Example icon-button with a menu"
>
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item>
<mat-icon>dialpad</mat-icon>
<span>Redial</span>
</button>
<button mat-menu-item disabled>
<mat-icon>voicemail</mat-icon>
<span>Check voice mail</span>
</button>
<button mat-menu-item>
<mat-icon>notifications_off</mat-icon>
<span>Disable alerts</span>
</button>
</mat-menu>
菜单的延时加载以及在调用的时候动态传参:
html
<mat-menu #lazyMenu="matMenu">
<ng-template matMenuContent let-name="name" let-hobby="hobby">
<button mat-menu-item>Settings</button>
<button mat-menu-item>Hobby is {{ hobby }}</button>
<button mat-menu-item>Log out {{ name }}</button>
</ng-template>
</mat-menu>
<button
mat-raised-button
[matMenuTriggerData]="{ name: 'Vishwas', hobby: 'football' }"
[matMenuTriggerFor]="lazyMenu"
>
Vishwas
</button>
<button
mat-raised-button
[matMenuTriggerData]="{ name: 'codevolution', hobby: 'teaching' }"
[matMenuTriggerFor]="lazyMenu"
>
Codevolution
</button>
这段代码是使用了 Angular Material 组件库中的 mat-menu
组件来创建一个下拉菜单,并且这个菜单的内容是通过 ng-template
动态生成的。下面是对这段代码的详细解释:
1. <mat-menu #lazyMenu="matMenu">
这一行定义了一个 mat-menu
组件,它是一个下拉菜单。#lazyMenu="matMenu"
是一个模板引用变量,它允许我们在模板的其他部分引用这个菜单。
2. <ng-template matMenuContent let-name="name" let-hobby="hobby">
这里使用了一个 ng-template
标签来定义菜单的内容。matMenuContent
是一个指令,它告诉 Angular 这个模板是用来渲染 mat-menu
的内容的。
let-name="name"
和 let-hobby="hobby"
是模板输入变量的声明。这些变量将从触发菜单打开的数据(通过 [matMenuTriggerData]
传递)中获取对应的值。
3. 菜单项
html
<button mat-menu-item>Settings</button>
<button mat-menu-item>Hobby is {{hobby}}</button>
<button mat-menu-item>Log out {{name}}</button>
这三行定义了三个菜单项。每个菜单项都是一个 button
元素,使用了 mat-menu-item
指令来将其标记为菜单项。
- 第一个菜单项是静态的,只显示"Settings"文本。
- 第二个菜单项显示"Hobby is "后跟从触发数据中获取的
hobby
值。 - 第三个菜单项显示"Log out "后跟从触发数据中获取的
name
值。
4. 触发按钮
下面是两个按钮,它们都用作触发下拉菜单的按钮:
html
<button mat-raised-button
[matMenuTriggerData]="{ name: 'Vishwas', hobby: 'football'}"
[matMenuTriggerFor]="lazyMenu">
Vishwas
</button>
和
html
<button mat-raised-button
[matMenuTriggerData]="{ name: 'codevolution', hobby: 'teaching'}"
[matMenuTriggerFor]="lazyMenu">
Codevolution
</button>
这两个按钮都使用了 mat-raised-button
指令来应用 Material Design 的样式。
[matMenuTriggerData]
是一个属性绑定,它传递一个对象,该对象包含要显示在菜单中的数据(在这里是name
和hobby
)。[matMenuTriggerFor]="lazyMenu"
是一个属性绑定,它指定了当按钮被点击时要打开哪个菜单。在这里,它引用了之前定义的mat-menu
组件的模板引用变量lazyMenu
。
这段代码创建了一个动态内容的下拉菜单,该菜单的内容(特别是 name
和 hobby
)是根据触发菜单打开的按钮所传递的数据来确定的。当用户点击任何一个按钮时,都会打开一个包含该用户名字和爱好的菜单。
11. Lists
相关的 module 名叫 MatListModule
, 记得在使用之前引用。
html
<mat-list dense>
<mat-list-item>item1</mat-list-item>
<mat-list-item>item2</mat-list-item>
<mat-list-item>item3</mat-list-item>
</mat-list>
<mat-nav-list dense>
<a mat-list-item href="#"> Home </a>
<a mat-list-item href="#"> About </a>
<a mat-list-item href="#"> Services </a>
</mat-nav-list>
效果如图所示:
带图标的多行 list:
html
<mat-list>
<mat-list-item>
<mat-icon matListIcon>home</mat-icon>
<h3 matLine>Heading</h3>
<p matLine>Line</p>
</mat-list-item>
<mat-list-item>
<mat-icon matListIcon>menu</mat-icon>
<h3 matLine>Heading</h3>
<p matLine>Line</p>
</mat-list-item>
<mat-list-item>
<mat-icon matListIcon>help</mat-icon>
<h3 matLine>Heading</h3>
<p matLine>Line</p>
</mat-list-item>
</mat-list>
效果如下所示:
12. 分割符 MatDividerModule
使用列表等组件的时候,希望有更好的排列方式,这个时候一般使用的就是 MatDividerModule. 这个组件就是用来分割其它组件的。
下面是添加了分割符号的列表,比之前好看多了。
html
<mat-list>
<mat-list-item>
<mat-icon matListIcon>home</mat-icon>
<h3 matLine>Heading</h3>
<p matLine>Line</p>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>
<mat-icon matListIcon>menu</mat-icon>
<h3 matLine>Heading</h3>
<p matLine>Line</p>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>
<mat-icon matListIcon>help</mat-icon>
<h3 matLine>Heading</h3>
<p matLine>Line</p>
</mat-list-item>
<mat-divider></mat-divider>
</mat-list>
效果如下:
13. Grids
相关的 module 名叫 MatGridListModule
, 记得在使用之前引用。就是 CSS 中的 网格布局感觉。
html
<mat-grid-list cols="2" rowHeight="fit" style="height: 200px" gutterSize="10px">
<!-- <mat-grid-list cols="2" rowHeight="2:1"> -->
<!-- <mat-grid-list cols="2" rowHeight="100px"> -->
<mat-grid-tile colspan="1">Title 1</mat-grid-tile>
<mat-grid-tile>Title 2</mat-grid-tile>
<mat-grid-tile>Title 3</mat-grid-tile>
<mat-grid-tile>Title 4</mat-grid-tile>
</mat-grid-list>
14. Expansion
相关的 module 名叫 MatExpansionModule
, 记得在使用之前引用。这个是一个可以伸缩的标题栏。
html
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title> Angular Fundamentals </mat-panel-title>
<mat-panel-description> Total Duration: 3 hours </mat-panel-description>
</mat-expansion-panel-header>
</mat-expansion-panel>
效果如下所示:
添加内容和按钮之后:
html
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title> Angular Fundamentals </mat-panel-title>
<mat-panel-description> Total Duration: 3 hours </mat-panel-description>
</mat-expansion-panel-header>
<p>This is the pannel content. Add course details.</p>
<mat-action-row>
<button mat-button>Enroll</button>
</mat-action-row>
</mat-expansion-panel>
Expansion 组:如果我们使用 mat-accordion 包裹多个 mat-expansion-panel 在内,那么这些被包裹的 expansion-panel 会被认为是同一组。在同一个组里面的 panel 具有一个特性就是,其它 panel 展开的时候,剩余 panel 会收起来。
html
<mat-accordion>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title> Angular Fundamentals </mat-panel-title>
<mat-panel-description> Total Duration: 3 hours </mat-panel-description>
</mat-expansion-panel-header>
<p>This is the pannel content. Add course details.</p>
<mat-action-row>
<button mat-button>Enroll</button>
</mat-action-row>
</mat-expansion-panel>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title> Angular Fundamentals </mat-panel-title>
<mat-panel-description> Total Duration: 3 hours </mat-panel-description>
</mat-expansion-panel-header>
<p>This is the pannel content. Add course details.</p>
<mat-action-row>
<button mat-button>Enroll</button>
</mat-action-row>
</mat-expansion-panel>
</mat-accordion>
效果如下:
然而,如果不需要这个特性,可以简单的在 mat-accordion 这个外层标签上设置 multi="true" 即可!
而如果你需要隐藏右上角的 toggle 标签,只需要在 mat-accordion 这个外层标签上设置 hideToggle 即可!这个时候只需要点击每一个 panel 的标题栏即可展开或者收缩这个 panel.
15. Cards
相关的 module 名叫 MatCardModule
, 记得在使用之前引用。这个是项目中经常会用到的卡片组件。
html
<mat-card>Basic Card </mat-card>
<mat-divider></mat-divider>
<mat-card>
<mat-card-title> Card Title </mat-card-title>
<mat-card-content> This is card content. </mat-card-content>
<mat-card-actions align="end">
<button mat-flat-button color="primary">Login</button>
</mat-card-actions>
</mat-card>
上面的代码是 Cards 组件简单的使用方法。其效果如下所示:
Material 中的这个 -actions 标签非常的有意思!
16. Tabs
相关的 module 名叫 MatTabsModule
, 记得在使用之前引用。这个就是 Tabs 用来切换卡片的。
html
<mat-tab-group
#tabRef
(selectedTabChange)="handleTabChange(tabRef.selectedIndex!)"
>
<mat-tab label="Angular">Angular</mat-tab>
<mat-tab label="React">React</mat-tab>
<mat-tab label="Vue">Vue</mat-tab>
</mat-tab-group>
{{ tabRef.selectedIndex }}
上述代码完成了不同 tabs 之间的切换并且将当前选择的 tab 的序列号通过事件传递给了组件。
17. Stepper
相关的 module 名叫 MatStepperModule
, 记得在使用之前引用。
html
<mat-horizontal-stepper>
<mat-step label="Shipping Address">
<p>Shipping Address Details</p>
</mat-step>
<mat-step label="Billing Address">
<p>Billing Address Details</p>
</mat-step>
<mat-step label="Place Order">
<p>Order Details</p>
</mat-step>
</mat-horizontal-stepper>
效果如下所示:
只能说确实 cool!
我们可以通过在 stepper 中添加按钮并绑定特定属性的当时方便的实现前进和后退:
html
<mat-horizontal-stepper>
<mat-step label="Shipping Address">
<p>Shipping Address Details</p>
</mat-step>
<mat-step label="Billing Address">
<p>Billing Address Details</p>
<div>
<button mat-button matStepperPrevious>Previous</button>
<button mat-button matStepperNext>Next</button>
</div>
</mat-step>
<mat-step label="Place Order">
<p>Order Details</p>
</mat-step>
</mat-horizontal-stepper>
可以看到第二步里面出现了两个按钮:
通过 completed 和 linear 属性可以控制 stepper 能否向下走:
html
<mat-horizontal-stepper linear="">
<mat-step label="Shipping Address" completed="false">
<p>Shipping Address Details</p>
</mat-step>
<mat-step label="Billing Address" completed="false">
<p>Billing Address Details</p>
<div>
<button mat-button matStepperPrevious>Previous</button>
<button mat-button matStepperNext>Next</button>
</div>
</mat-step>
<mat-step label="Place Order" completed="false">
<p>Order Details</p>
</mat-step>
</mat-horizontal-stepper>
在代码中,我们设置 linear 表示要前面的步骤完成了后面的步骤才会显示出来。同时设置 completed 属性告诉组件哪个步骤完成了。
此外,我们可以给 mat-step 上添加 optional 表示这一步是可选的。
除了有 mat-horizontal-stepper 还有 mat-vertical-stepper
下面的组件都是和表单相关的:
18. Input
我们需要引入的 module 有:MatFormFileModule 和 MatInputModule.
html
<mat-form-field>
<mat-label>Name</mat-label>
<input matInput />
</mat-form-field>
通过 floatLabel 这个属性你可以关闭或者打开上面很酷的悬浮样式。
你可以设置其值为 never 或者 always.
你可以设置 input 上面的 required 属性,这样表示必填项。
注意 required 是设置在 input 上面的,而如果你的整个表单都不需要 * , 你可以在 mat-form-field 上面设置 hideRequiredMarker, 这样就算是必填项也不会将 * 显示出来。
我们还可以给 input 方便的添加 hint: <mat-hint align="end">Min 5 characters</mat-hint>
通过设置 mat-form-field 上面名为 appearance 属性的值为 legacy 或者 standard fill outline可以直接改变整个表单的样式。通过设置 color 属性可以直接改变整个表单的颜色 accent warn。
19. Select
我们需要引入的 module 有:MatSelectModule.
html
<mat-form-field floatLabel="always" hideRequiredMarker="false">
<mat-select>
<mat-label>Topic</mat-label>
<mat-option value="angular">Angular</mat-option>
<mat-option value="react">React</mat-option>
<mat-option value="vue">Vue</mat-option>
</mat-select>
</mat-form-field>
双向绑定的 Select:
html
<mat-form-field>
<mat-label>Topic</mat-label>
<mat-select [(value)]="selectedValue">
<mat-option value="angular">Angular</mat-option>
<mat-option value="react">React</mat-option>
<mat-option value="vue">Vue</mat-option>
</mat-select>
</mat-form-field>
{{ selectedValue }}
分组 Select:
html
<mat-form-field>
<mat-label>Topic</mat-label>
<mat-select [(value)]="selectedValue">
<mat-option>None</mat-option>
<mat-optgroup label="Web">
<mat-option value="angular">Angular</mat-option>
<mat-option value="react">React</mat-option>
<mat-option value="vue">Vue</mat-option>
</mat-optgroup>
<mat-optgroup label="Mobile">
<mat-option value="ionic">Ionic</mat-option>
<mat-option value="reactnative">React Native</mat-option>
</mat-optgroup>
</mat-select>
</mat-form-field>
{{ selectedValue }}
多选 Select,只需要在 mat-select 这个标签上设置 multiple
就可以完成多选了。
20. Autocomplete
我们需要引入的 module 有:MatAutocompleteModule. 这个组件的作用是对 input 进行了扩展,在输入的时候能够提供给用户方便的选项。
html
<mat-form-field>
<input type="text" matInput [matAutocomplete]="auto" />
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let option of options" [value]="option">
{{ option }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
{{ selectedValue }}
效果如下:
但是,如果我们的 options 不是简单的数组,而是具有复杂结构的数组,这个时候我们可以定义一个 displayFn 来定制解析数组中的数据:
ts
objOptions = [{
name: 'angular',
}, {
name: 'react',
}, {
name: 'vue',
}];
displayFn(option: any) {
return option.name;
}
html
<mat-form-field>
<input type="text" matInput [matAutocomplete]="auto" />
<mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn">
<mat-option *ngFor="let option of objOptions" [value]="option">
{{ option.name }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
{{ selectedValue }}
注意上面的代码中用了 [displayWith]="displayFn"
21. FormsModule ReactiveFormsModule
这两个 module 记得在自己封装的 material module 之前引入,如下图所示:
然后来到我们的根组件中引入 FormControl:
ts
import { FormControl } from '@angular/forms';
import { Observable, startWith, map } from 'rxjs';
...
myControl = new FormControl();
filterOptions: Observable<string[]>;
ngOnInit() {
this.filterOptions = this.myControl.valueChanges.pipe(
startWith(''),
map(value => this._filter(value))
)
}
private _filter(value: string): string[] {
const filterValue = value.toLowerCase();
return this.options.filter(option => option.toLowerCase().includes(filterValue))
}
最后在 html 中使用表格的 controller:
html
<mat-form-field>
<input
type="text"
matInput
[matAutocomplete]="auto"
[formControl]="myControl"
/>
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let option of filterOptions | async" [value]="option">
{{ option }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
{{ selectedValue }}
对上面的代码进行解释:
21.1 TypeScript 代码部分
- 引入必要的模块:
ts
import { FormControl } from '@angular/forms';
import { Observable, startWith, map } from 'rxjs';
这里引入了FormControl
用于创建表单控件,并从rxjs
中引入了Observable
, startWith
, 和 map
用于处理异步数据流。
- 初始化FormControl和Observable:
ts
myControl = new FormControl();
filterOptions: Observable<string[]>;
myControl
是一个新的FormControl
实例,它代表了一个表单输入控件。filterOptions
是一个Observable
,它将包含过滤后的选项列表。
- 在
ngOnInit
生命周期钩子中设置数据流:
ts
ngOnInit() {
this.filterOptions = this.myControl.valueChanges.pipe(
startWith(''),
map(value => this._filter(value))
)
}
在组件初始化时,ngOnInit
方法会被调用。这里,我们监听myControl
的值变化,并通过pipe
操作符来处理这些变化。startWith('')
确保在没有任何输入时也能触发一次数据流(即初始化时),map
则用于将每次输入变化映射到过滤后的选项列表。
- 实现过滤函数:
ts
private _filter(value: string): string[] {
const filterValue = value.toLowerCase();
return this.options.filter(option => option.toLowerCase().includes(filterValue))
}
_filter
方法根据用户的输入来过滤options
数组(这个数组应该在类的其他部分被定义和初始化)。过滤是通过将输入和选项都转换为小写,并检查每个选项是否包含输入的文本来实现的。
21.2 HTML 代码部分
- 使用Material的表单和自动完成组件:
html
<mat-form-field>
<input type="text" matInput [matAutocomplete]="auto" [formControl]="myControl" />
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let option of filterOptions | async" [value]="option">
{{ option }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
<mat-form-field>
是Material的表单字段组件。<input>
元素与FormControl
实例(myControl
)绑定,并设置为自动完成的输入源。<mat-autocomplete>
是Material的自动完成组件,它与输入字段相关联。*ngFor
指令用于循环遍历filterOptions
中的每个选项(这里使用了async
管道来处理Observable)。
- 显示选中的值:
html
{{ selectedValue }}
这部分是显示选中的值,但需要注意的是,selectedValue
变量在提供的代码片段中没有定义。通常,你需要在组件的TypeScript部分添加一个[(ngModel)]
绑定或在选项被选中时更新这个值。如果要在选项被选中时更新selectedValue
,你可以使用(optionSelected)
事件。例如:
html
<mat-autocomplete (optionSelected)="selectedValue = $event.option.value">
这样,每当用户从自动完成列表中选择一个选项时,selectedValue
就会被更新为该选项的值。
这段代码实现了一个基于用户输入的实时过滤的自动完成功能,使用了Angular Material的组件和Reactive Forms的FormControl
。
22. Checkbox
我们需要引入的 module 有:MatCheckboxModule.
html
<mat-checkbox> Subscribe </mat-checkbox>
<br />
<mat-checkbox labelPosition="before"> Subscribe </mat-checkbox>
<br />
<mat-checkbox color="primary"> Subscribe </mat-checkbox>
<br />
<mat-checkbox color="warn"> Subscribe </mat-checkbox>
Radio
我们需要引入的 module 有:MatRadioModule.
html
<mat-radio-group>
<mat-radio-button value="angular" color="primary">Angular</mat-radio-button>
<mat-radio-button value="react" color="primary">React</mat-radio-button>
<mat-radio-button value="vue" color="warn">Vue</mat-radio-button>
</mat-radio-group>
我们用 group 将它们包裹起来它们自己就互斥了!
23. Datepicker
我们需要引入的 module 有:MatDatepickerModule 和 MatNativeDateModule.
基本使用:
html
<mat-form-field>
<input matInput [matDatepicker]="myDatePicker" />
<mat-datepicker-toggle [for]="myDatePicker" matSuffix></mat-datepicker-toggle>
<mat-datepicker #myDatePicker startView="multi-year"></mat-datepicker>
</mat-form-field>
效果:
设置日期的上下限:
html
<mat-form-field>
<input
matInput
[matDatepicker]="myDatePicker"
[min]="minDate"
[max]="maxDate"
/>
<mat-datepicker-toggle [for]="myDatePicker" matSuffix></mat-datepicker-toggle>
<mat-datepicker #myDatePicker startView="multi-year"></mat-datepicker>
</mat-form-field>
ts
minDate = new Date();
maxDate = new Date(2024, 12, 31);
效果为:
设置日期过滤器:
html
<mat-form-field>
<input
matInput
[matDatepicker]="myDatePicker"
[matDatepickerFilter]="dateFilter"
/>
<mat-datepicker-toggle [for]="myDatePicker" matSuffix></mat-datepicker-toggle>
<mat-datepicker #myDatePicker startView="multi-year"></mat-datepicker>
</mat-form-field>
ts
dateFilter = (date) => {
const day = date.getDay();
if (day !== 0 && day !== 6) {
return date;
} else {
return null;
};
}
效果为:
24. Tooltip
Angular Material 是一套丰富的 UI 组件库,用于构建 Angular 应用程序。Tooltip 是其中的一个组件,它提供了一种方式来显示元素的辅助信息,通常当用户将鼠标悬停在某个元素上时显示。
下面是关于 Angular Material Tooltip 组件的一些关键点,包括如何设置位置、持续时间和内容:
1. 安装和导入
首先,确保你已经安装了 Angular Material,并在你的 Angular 项目中导入了 MatTooltipModule
。
bash
npm install @angular/material
然后在你的模块文件中导入 MatTooltipModule
:
typescript
import { MatTooltipModule } from '@angular/material/tooltip';
import { NgModule } from '@angular/core';
@NgModule({
imports: [
// 其他模块
MatTooltipModule
],
// ...
})
export class AppModule { }
2. 基本使用
在你的组件的 HTML 模板中,你可以这样使用 Tooltip:
html
<button mat-button [matTooltip]="'这是 Tooltip 文本'">悬停我</button>
3. 设置 Tooltip 位置
Tooltip 组件提供了多种位置选项,你可以通过 matTooltipPosition
指令来设置 Tooltip 的位置。例如:
html
<button mat-button [matTooltip]="'这是 Tooltip 文本'" [matTooltipPosition]="'above'">悬停我</button>
可用的位置有:
above
:上方below
:下方left
:左侧right
:右侧before
:元素前after
:元素后
4. 设置 Tooltip 持续时间
Tooltip 的显示持续时间可以通过 matTooltipShowDelay
和 matTooltipHideDelay
指令来设置。单位是毫秒。
html
<button mat-button [matTooltip]="'这是 Tooltip 文本'" [matTooltipShowDelay]="1000" [matTooltipHideDelay]="500">悬停我</button>
5. 设置 Tooltip 内容
Tooltip 的内容可以通过 [matTooltip]
指令来设置,它可以是一个字符串或者是一个模板引用。
html
<!-- 字符串内容 -->
<button mat-button [matTooltip]="'这是 Tooltip 文本'">悬停我</button>
6. 动态控制 Tooltip 的显示和隐藏
你还可以通过属性绑定来动态控制 Tooltip 的显示和隐藏:
html
<button mat-button [matTooltip]="shouldShowTooltip ? 'Tooltip 显示' : ''" [matTooltipDisabled]="!shouldShowTooltip">悬停我</button>
在你的组件类中,你可以控制 shouldShowTooltip
的值来显示或隐藏 Tooltip。
或者使用 #tooltip
这个 ref:
html
<div>
<span> Click the following buttons to... </span>
<button mat-button
(click)="tooltip.show()"
aria-label="Show tooltip on the button at the end of this section"
class="example-action-button">
show
</button>
<button mat-button
(click)="tooltip.hide()"
aria-label="Hide tooltip on the button at the end of this section"
class="example-action-button">
hide
</button>
<button mat-button
(click)="tooltip.toggle()"
aria-label="Show/Hide tooltip on the button at the end of this section"
class="example-action-button">
toggle show/hide
</button>
</div>
<button mat-raised-button #tooltip="matTooltip"
matTooltip="Info about the action"
matTooltipPosition="right"
aria-tooltip="Button that displays and hides a tooltip triggered by other buttons">
Action
</button>
7. 自定义 Tooltip
除了上述基本设置外,你还可以自定义 Tooltip 的样式和行为,例如通过 CSS 来改变 Tooltip 的外观,或者通过事件监听来控制 Tooltip 的行为。
这些是 Angular Material Tooltip 组件的一些基本用法。根据你的具体需求,你可以进一步探索和定制 Tooltip 组件。
25. SnackBar
Angular Material 的 Snackbar 是一种轻量级的消息提示组件,用于向用户显示简短的消息或反馈。以下是关于如何使用 Angular Material Snackbar 的一些关键点,包括传递消息、自定义样式、延时取消、ref对象以及action事件。
1. 安装和导入
首先,确保你已经安装了 Angular Material,并在你的 Angular 项目中导入了 MatSnackBarModule
。
bash
npm install @angular/material
然后在你的模块文件中导入 MatSnackBarModule
:
typescript
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { NgModule } from '@angular/core';
@NgModule({
imports: [
// 其他模块
MatSnackBarModule
],
// ...
})
export class AppModule { }
2. 服务注入
在你的组件中,你需要注入 MatSnackBar
服务。
typescript
import { MatSnackBar } from '@angular/material/snack-bar';
import { Component } from '@angular/core';
@Component({
selector: 'app-snack-bar-example',
template: `<button (click)="openSnackBar()">打开 Snackbar</button>`
})
export class SnackBarExampleComponent {
constructor(public snackBar: MatSnackBar) { }
}
3. 传递消息
使用 MatSnackBar
服务的 open
方法来显示 Snackbar,并传递消息。
typescript
openSnackBar() {
this.snackBar.open('这是一条消息', '关闭', {
duration: 2000, // 持续时间
});
}
4. 自定义样式
你可以通过 CSS 来自定义 Snackbar 的样式。
css
/* app.component.css */
.custom-snack-bar-class {
background-color: #4caf50; /* 绿色背景 */
color: white; /* 白色文字 */
}
然后在调用 open
方法时,指定样式类:
typescript
openSnackBar() {
this.snackBar.open('这是一条自定义样式的消息', '关闭', {
panelClass: ['custom-snack-bar-class'], // 自定义样式类
duration: 2000,
});
}
5. 延时取消
可以通过 duration
选项来设置 Snackbar 的持续时间,单位为毫秒。如果设置为 0
,则 Snackbar 将不会自动消失。
typescript
openSnackBar() {
this.snackBar.open('这条消息将在 2 秒后消失', '关闭', {
duration: 2000,
});
}
6. ref对象
open
方法返回一个 MatSnackBarRef
对象,你可以通过这个对象来控制 Snackbar 的行为。
typescript
openSnackBar() {
const snackBarRef = this.snackBar.open('这条消息可以被手动关闭', '关闭', {
duration: 0, // 不自动消失
});
// 手动关闭 Snackbar
snackBarRef.afterDismissed().subscribe(() => {
console.log('Snackbar 已关闭');
});
}
7. action事件
你可以为 Snackbar 添加一个操作按钮,并监听点击事件。
typescript
openSnackBar() {
const snackBarRef = this.snackBar.open('这条消息有一个操作按钮', '撤销', {
duration: 2000,
});
snackBarRef.onAction().subscribe(() => {
console.log('操作按钮被点击');
});
}
8. 配置
你还可以通过全局配置来设置 Snackbar 的默认行为。
typescript
import { MatSnackBar, MatSnackBarConfig } from '@angular/material/snack-bar';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class GlobalSnackBarService {
constructor(private snackBar: MatSnackBar) {
const defaultConfig: MatSnackBarConfig<any> = {
duration: 2500,
horizontalPosition: 'right',
verticalPosition: 'bottom',
};
// this.snackBar.setDefaultConfig(defaultConfig);
}
openSnackBar(message: string, action: string = '') {
this.snackBar.open(message, action, {
panelClass: ['custom-snack-bar-class'], // 可以在这里添加自定义样式类
});
}
}
然后在组件中使用这个服务:
typescript
constructor(private globalSnackBarService: GlobalSnackBarService) { }
openSnackBar() {
this.globalSnackBarService.openSnackBar('这是一条全局配置的 Snackbar 消息');
}
以上就是 Angular Material Snackbar 组件的一些基本用法和配置选项。根据你的具体需求,你可以进一步探索和定制 Snackbar 组件。
26. Dialog
Angular Material 的 Dialog 组件用于创建模态对话框,可以用于显示重要的信息、表单、或者其他交互元素。以下是关于如何使用 Angular Material Dialog 的一些关键点,包括设置组件、展示 Dialog、设置标题、内容、底部按钮以及按钮上的回调,以及如何在打开 Dialog 时传递信息。
1. 安装和导入
首先,确保你已经安装了 Angular Material,并在你的 Angular 项目中导入了 MatDialogModule
。
bash
npm install @angular/material
然后在你的模块文件中导入 MatDialogModule
:
typescript
import { MatDialogModule } from '@angular/material/dialog';
import { NgModule } from '@angular/core';
@NgModule({
imports: [
// 其他模块
MatDialogModule
],
// ...
})
export class AppModule { }
2. 创建 Dialog 组件
创建一个 Angular 组件,这将作为 Dialog 的内容。
bash
ng generate component DialogContent
编辑 dialog-content.component.ts
:
typescript
import { Component } from '@angular/core';
@Component({
selector: 'app-dialog-content',
template: `
<h2 mat-dialog-title>这是标题</h2>
<mat-dialog-content>
<p>这是 Dialog 的内容。</p>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button mat-dialog-close>取消</button>
<button mat-button [mat-dialog-close]="true">确定</button>
</mat-dialog-actions>
`,
})
export class DialogContentComponent {}
3. 服务注入
在你的组件中,你需要注入 MatDialog
服务。
typescript
import { MatDialog } from '@angular/material/dialog';
import { Component } from '@angular/core';
import { DialogContentComponent } from './dialog-content.component';
@Component({
selector: 'app-dialog-example',
template: `<button (click)="openDialog()">打开 Dialog</button>`
})
export class DialogExampleComponent {
constructor(public dialog: MatDialog) { }
openDialog() {
const dialogRef = this.dialog.open(DialogContentComponent, {
width: '250px',
// 其他配置
});
dialogRef.afterClosed().subscribe(result => {
console.log('Dialog 的结果:', result);
});
}
}
4. 设置组件的标题、内容、底部按钮
在 Dialog 组件的模板中,你已经可以设置标题 <h2 mat-dialog-title>
,内容 <mat-dialog-content>
,以及底部按钮 <mat-dialog-actions>
。
5. 按钮上的回调
在 Dialog 组件中,你可以通过 mat-dialog-close
属性来设置按钮的回调。当按钮被点击时,Dialog 将关闭,并返回一个值。
html
<!-- 在 Dialog 组件模板中 -->
<button mat-button (click)="closeDialog('取消')">取消</button>
<button mat-button (click)="closeDialog(true)">确定</button>
在 Dialog 组件的 TypeScript 文件中:
typescript
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
export class DialogContentComponent {
constructor(
public dialogRef: MatDialogRef<DialogContentComponent>,
@Inject(MAT_DIALOG_DATA) public data: any) {}
closeDialog(result: any): void {
this.dialogRef.close(result);
}
}
6. 打开的时候往其中传递信息
你可以通过 data
属性在打开 Dialog 时传递信息。
typescript
openDialog() {
const dialogRef = this.dialog.open(DialogContentComponent, {
width: '250px',
data: { message: '这是传递给 Dialog 的信息' }
});
dialogRef.afterClosed().subscribe(result => {
console.log('Dialog 的结果:', result);
});
}
在 Dialog 组件中接收传递的信息:
typescript
export class DialogContentComponent {
constructor(
public dialogRef: MatDialogRef<DialogContentComponent>,
@Inject(MAT_DIALOG_DATA) public data: any) {}
ngOnInit() {
console.log('传递给 Dialog 的信息:', this.data.message);
}
// ...
}
以上就是 Angular Material Dialog 组件的基本用法,包括设置组件、展示 Dialog、设置标题、内容、底部按钮以及按钮上的回调,以及如何在打开 Dialog 时传递信息。根据你的具体需求,你可以进一步探索和定制 Dialog 组件。
27. HammerJS
和 Angular Material 相关的一个库是 HammerJS. Hammer.js 是一个开源的 JavaScript 库,它提供了对触摸手势的识别和处理功能。这个库允许开发者为他们的网页和移动应用添加多点触控手势,例如平移(pan)、缩放(pinch)、旋转(rotate)、滑动(swipe)等。
以下是一些关于 Hammer.js 的关键点:
兼容性
Hammer.js 旨在兼容各种设备,包括手机、平板和桌面设备。它支持现代浏览器和旧版浏览器,如 Internet Explorer 10+。
手势识别
Hammer.js 可以识别多种手势,包括但不限于:
- 拖拽(drag)
- 缩放(pinch)
- 旋转(rotate)
- 滑动(swipe)
- 长按(press)
- 轻触(tap)
多点触控
Hammer.js 支持多点触控手势,这意味着它可以同时处理多个触摸点,这对于实现缩放和旋转等手势非常有用。
链式手势
Hammer.js 允许你创建手势链,这意味着你可以将多个手势组合在一起,以创建更复杂的交互。
快速和轻量
Hammer.js 被设计为快速和轻量级,这意味着它不会显著影响你的网页或应用的性能。
使用示例
以下是如何在网页中使用 Hammer.js 的一个基本示例:
- 首先,你需要在你的 HTML 文件中包含 Hammer.js 库:
html
<script src="path/to/hammer.min.js"></script>
- 然后,你可以创建一个
Hammer
实例,并将其附加到一个 DOM 元素上:
javascript
var myElement = document.getElementById('myElement');
var mc = new Hammer(myElement);
- 接下来,你可以添加手势监听器:
javascript
mc.on('swipeleft', function(event) {
console.log('Swipe left detected');
});
- 你还可以通过
recognizers
选项来配置手势:
javascript
var options = {
recognizers: [
[Hammer.Pan, { direction: Hammer.DIRECTION_HORIZONTAL }],
[Hammer.Rotate]
]
};
var mcWithOptions = new Hammer(myElement, options);
社区和维护
Hammer.js 有一个活跃的社区,并且得到了持续的维护和更新。
替代品
尽管 Hammer.js 是一个流行的手势库,但还有其他一些库也提供了类似的功能,如 FastClick、Touchy、Swipe.js 等。
Hammer.js 是构建交互式触摸界面的强大工具,它的灵活性和易用性使其成为许多前端开发者的首选。