Angular Material design设计
官网:
https://meterial.io/components
优秀的Meterial design站点:
http://materialdesignblog.com/
并不是万能的,都有约束条件。
优点:兼容性好,可扩展性强,可测试性好,对主题的支持好。
缺点:组件不是特别丰富。
安装:
//其它方式
$ sudo cnpm i --save @angular/material@2.0.0-beta.7
$ sudo yarn add @angular/material --save
$ npm i @angular/material --save
安装的版本是"@angular/material": "^7.1.0",
有个依赖要手动安装
$ sudo yarn add @angular/cdk@6.4.6 --save
如果是用ng add @angular/material 会自动安装cdk(Component Dev Kit)依赖。
一、相关报错
1、控制台报警告:Could not find Angular Material core theme。
在styles.scss中引入angular materail主题:
内建主题有这几种:
可以用scss自定义主题。
2、ERROR Error: Found the synthetic listener @transform.start. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.
二、Material组件
1、SidebarComponent侧边栏导航:
https://material.angular.io/components/sidenav/overview
<mat-sidenav-container> <mat-sidenav #sidenav> <app-sidebar></app-sidebar> </mat-sidenav> <div class="site"> <header> <app-header></app-header> </header> <main> <button (click)="sidenav.open()">打开侧边栏</button> </main> <footer> <app-footer></app-footer> </footer> </div> </mat-sidenav-container>
根容器<mat-sidenav-container>
3种模式:over, side和push
- over模式【默认】
- side模式
- push模式
- position="end"
<mat-sidenav #sidenav mode="push" position="end">
侧边栏跑右边了,默认start。最多可以有2个侧边栏。
<mat-sidenav-container> <mat-sidenav #sidenav1 mode="push" position="end"> <app-sidebar></app-sidebar> </mat-sidenav> <mat-sidenav #sidenav2 mode="push" position="start"> <app-sidebar></app-sidebar> </mat-sidenav> <div class="site"> <header> <app-header></app-header> </header> <main> <button (click)="sidenav1.open()">打开右边侧边栏</button> <button (click)="sidenav2.open()">打开左边侧边栏</button> </main> <footer> <app-footer></app-footer> </footer> </div> </mat-sidenav-container>
- toogle方法:类似open
<mat-sidenav-container> <mat-sidenav #sidenav mode="side" > <app-sidebar></app-sidebar> </mat-sidenav> <div class="site"> <header> <app-header></app-header> </header> <main> <button (click)="sidenav.toggle()">打开侧边栏</button> </main> <footer> <app-footer></app-footer> </footer> </div> </mat-sidenav-container>
2、Toolbar完成头部和尾部
https://material.angular.io/components/toolbar/overview
用途:一般用于头部,标题栏
颜色primary紫色,accent黄色,warn红色。
主色:primary
配色:accent
用官方的material io 的COLOR TOOL可以调出合适的颜色。主色深紫,辅助色黄色效果如下。
1、居中用flex怎么实现?
在想居中元素两边都放了自动扩大充满的元素。
在styles.scss中加入
.fill-remaining-space { // 使用 flexbox 填充剩余空间 // @angular/material 中的很多控件使用了 flex 布局 flex: 1 1 auto; }
<mat-toolbar color="primary"> <span class="fill-remaining-space"></span> <span>© strof 版权声明</span> <span class="fill-remaining-space"></span> </mat-toolbar>
2、两行内容怎么实现?
<mat-toolbar color="primary"> <mat-toolbar-row> <span class="fill-remaining-space"></span> <span>© starof 版权声明</span> <span class="fill-remaining-space"></span> </mat-toolbar-row> <mat-toolbar-row> <span class="fill-remaining-space"></span> <span>这是第二行</span> <span class="fill-remaining-space"></span> </mat-toolbar-row> </mat-toolbar>
3、菜单button调出左边sidebar
@Output() toggle = new EventEmitter(); constructor() { } ngOnInit(): void { } openSideBar(){ this.toggle.emit('clicked'); }
<app-header (toggle)="sidenav.open()"></app-header>
4、 用一个icon代替头部的菜单2个文字
https://material.angular.io/components/icon/overview
推荐使用图标字体,基于字体的,好处占用资源小,矢量图,内建material icon支持。
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<button mat-icon-button (click)="openSidebar()"> <mat-icon class="material-icons">menu</mat-icon> </button>
想要使用其它图标直接,去https://material.io/tools/icons/ 找到图标对应文字替换掉即可。
开始按钮的背景颜色不透明,需要把button也变成meterial风格,给button上加上 mat-icon-button,并且需要导入MatButtonModule。
5、MatIcon也支持SVG图标。
找SVG资源,http://iconfont.cn/ 阿里爸爸矢量图标库
把下载好的SVG放在项目的assets中。
最终效果:
constructor(private iconRegistry: MatIconRegistry, private sanitizer: DomSanitizer) { iconRegistry.addSvgIcon('gift', sanitizer.bypassSecurityTrustResourceUrl('assets/gift.svg')); }
<mat-icon svgIcon="gift"></mat-icon>
问题,每次使用一个新图标都要注册一遍。图标分散在各个组件的constructor中,难以维护。
更好的做法:
在app下创建一个utils目录,在utils里建一个svg.util.ts。
import { MatIconRegistry } from "@angular/material"; import { DomSanitizer } from "@angular/platform-browser"; export const loadSvgResources = (ir: MatIconRegistry, ds: DomSanitizer) => { ir.addSvgIcon("gift", ds.bypassSecurityTrustResourceUrl("assets/gift.svg")); };
不在组件的constructor里导入里,在core module里只加载一次。
export class CoreModule { constructor( @Optional() @SkipSelf() parent: CoreModule, //加上@SkipSelf()注解 ir: MatIconRegistry, ds: DomSanitizer ) { if (parent) { throw new Error("模块已经存在,不能再次加载"); } loadSvgResources(ir, ds); } }
这样其它页面只要用就可以,解决了装载资源分散的问题。
3、Input组件matInputModule
可以通过color取值warn,accent等来改变input输入框的颜色。
可以通过floatLabel取值float,always,auto来改变Label显示方式。
可以设置hintLabel或者<mat-hint>来添加更多提示信息。
可以通过给<mat-form-field>里的元素设置matSuffix指令来给输入框添加后缀,设置matPrefix指令加前缀。
https://material.angular.io/components/form-field/overview
<mat-form-field class="example-full-width" color="warn" floatLabel="auto" hintLabel="Max 10 characters"> <input #input matInput placeholder="您的email"> <span matSuffix>@gmail.com</span> <mat-hint align="end">{{input.value?.length || 0}}/10</mat-hint> </mat-form-field>
4、Card组件和Button组件
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 |
<mat-card class="example-card"> <mat-card-header> <mat-card-title>每日佳句</mat-card-title> <mat-card-subtitle>满足感在于不断的努力,而不是现有成就。全心努力定会胜利满满。</mat-card-subtitle> </mat-card-header> <img mat-card-image src="/assets/images/quote_fallback.jpg" alt=""> <mat-card-content> Satisfaction lies in the effort, not in the attainment. Full effort is full victory. </mat-card-content> </mat-card>
5、List
https://material.angular.io/components/list/overview
用途:一般用于列表,包括多行列表,带图标列表,带头像列表,密集列表(dense list)和多段列表。
分为<mat-list>
和<mat-nav-list>
在侧滑菜单中使用List。
matNavList鼠标hover上去会有高亮效果。
<mat-nav-list> <h3 mat-subheader>项目</h3> <mat-list-item> <mat-icon mat-list-icon svgIcon="projects"></mat-icon> <h4 mat-line>项目首页</h4> <p mat-line mat-subheader> 查看您的所有项目</p> </mat-list-item> <h3 mat-subheader>日历</h3> <mat-list-item> <mat-icon mat-list-icon svgIcon="month"></mat-icon> <h4 mat-line>月视图</h4> <p mat-line mat-subheader> 按月查看您的任务</p> </mat-list-item> <mat-list-item> <mat-icon mat-list-icon svgIcon="week"></mat-icon> <h4 mat-line>周视图</h4> <p mat-line mat-subheader> 按周查看您的任务</p> </mat-list-item> <mat-list-item> <mat-icon mat-list-icon svgIcon="day"></mat-icon> <h4 mat-line>日视图</h4> <p mat-line mat-subheader> 按天查看您的任务</p> </mat-list-item> </mat-nav-list>
Dense list会让列表的字体shrink来显示更多内容。用法<mat-nav-list dense>。
把日式图的图标改变成当天的日前,在svg.util.ts中加入提前准备好的30天日期day1.svg到day3-.svg.
import { MatIconRegistry } from "@angular/material"; import { DomSanitizer } from "@angular/platform-browser"; export const loadSvgResources = (ir: MatIconRegistry, ds: DomSanitizer) => { const imgDir = "assets/img"; const sidebarDir = `${imgDir}/sidebar`; const dayDir = `${imgDir}/days`; ir.addSvgIcon( "day", ds.bypassSecurityTrustResourceUrl(`${sidebarDir}/day.svg`) ); ir.addSvgIcon( "month", ds.bypassSecurityTrustResourceUrl(`${sidebarDir}/month.svg`) ); ir.addSvgIcon( "project", ds.bypassSecurityTrustResourceUrl(`${sidebarDir}/project.svg`) ); ir.addSvgIcon( "projects", ds.bypassSecurityTrustResourceUrl(`${sidebarDir}/projects.svg`) ); ir.addSvgIcon( "week", ds.bypassSecurityTrustResourceUrl(`${sidebarDir}/week.svg`) ); const days =[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]; days.forEach((d)=>{ ir.addSvgIcon( `day${d}`, ds.bypassSecurityTrustResourceUrl(`${dayDir}/day${d}.svg`) ); }); };
在sidebar.component.ts中引入一个类库day-fns。
npm uninstall --save date-fns //先安装date-fns npm install --save-dev @types/date-fns //再date-fns针对typescript也可以使用的类型
import { Component, OnInit } from '@angular/core'; import {getDate} from 'date-fns'; //getDate取得是一个月的几号 @Component({ selector: 'app-sidebar', templateUrl: './sidebar.component.html', styleUrls: ['./sidebar.component.scss'] }) export class SidebarComponent implements OnInit { today = 'day'; constructor() { } ngOnInit() { this.today=`day${getDate(new Date())}`; //today对应icon的名字 } }
模版中icon对应到today。
6、GridList
用途:用于相似的数据展示,尤其是图片,类似相册等
行为很像表格,有colspan, rowspan属性
<mat-grid-list cols="8" rowHeight="1:1"> <mat-grid-tile colspan="2"> 1 </mat-grid-tile> <mat-grid-tile> 2 </mat-grid-tile> <mat-grid-tile> 3 </mat-grid-tile> <mat-grid-tile> 4 </mat-grid-tile> <mat-grid-tile rowspan="2"> 5 </mat-grid-tile> <mat-grid-tile> 6 </mat-grid-tile> <mat-grid-tile> 7 </mat-grid-tile> <mat-grid-tile> 8 </mat-grid-tile> <mat-grid-tile> 9 </mat-grid-tile> <mat-grid-tile> 10 </mat-grid-tile> <mat-grid-tile> 11 </mat-grid-tile> <mat-grid-tile> 12 </mat-grid-tile> <mat-grid-tile> 13 </mat-grid-tile> <mat-grid-tile> 14 </mat-grid-tile> </mat-grid-list>
注册页面头像列表可以用GridList实现。
7、dialog
https://material.angular.io/components/dialog/overview
对话框很特殊,和menu一样需要在模块中的entryComponents中声明。
由于它们是需要事先完全隐藏,或者隐藏一部分。一开始模块加载的时候是看不到dialog的,点击按钮才能弹出。对于这种情况,需要一个预加载,就需要放在模块的entryComponents中。
从支持 Ivy 的 9.0.0 开始,entryComponents
属性就不再需要了,参见弃用指南。
1、从调用者向Dialog传递数据
传递数据:
不能像其它组件一样,通过路由去传递数据。
需要从在的调用者去写,在按钮的click事件中写:传入dialog的类,用一个字典传入任意数据。
const dialogRef = dialog.open(YourDialog, {data:'Your data'});
接收数据:
在Dialog的构造中注入MD_DIALOG_DATA就可以取得数据。
constructor(@Inject(MAT_DIALOG_DATA) private data: any) { }
2、在Dialog把数据往回传,传给调用者。
弹窗组件中通过dialogRef关闭传值。
调用者通过注册afterClosed事件拿到数据。
//NewProject 组件中注入MatDialogRef constructor(@Inject(MAT_DIALOG_DATA) private data: any, public dialogRef: MatDialogRef<NewProjectComponent>, ) { } //在点击保存按钮时候发送数据 onSave() { this.dialogRef.close('I received your message'); }
//调用者open的时候拿到一个引用,注册afterClosed事件返回一个Observable openNewProjectDialog() { // this.dialog.open(NewProjectComponent,{data:'this is a dialog'}); const dialogRef = this.dialog.open(NewProjectComponent, { data: "this is a dialog" }); dialogRef.afterClosed().subscribe((result)=>{ console.log(result); }); }
3、Dialog样式支持主题
默认不支持主题,
Dialog是一个浮动层,通过注入OverlayContainer来设置样式。利用data传值动态设置。
//注入OverlayContainer constructor(@Inject(MAT_DIALOG_DATA) private data: any, public dialogRef: MatDialogRef<NewProjectComponent>, private oc: OverlayContainer) { } //通过传入dark来切换class ngOnInit(): void { console.log(JSON.stringify(this.data)); const themeClass = this.data.dark ? 'myapp-dark-theme' : ''; this.oc.getContainerElement().classList.add(themeClass); }
8、autoComplete
https://material.angular.io/components/autocomplete/overview
mat-autocomplete配合matInput输入框来用,成对出现。mapInput中指定引用[matAutocomplete="auto"]。
在mat-autocomplete中指定#auto=matAutocomplete。
<form> <h2 mat-dialog-title>邀请组员</h2> <div mat-dialog-content> <mat-form-field class="full-width"> <input type="text" matInput placeholder="组员姓名" [matAutocomplete]="autoMembers"> </mat-form-field> </div> <div mat-dialog-actions> <button type="button" mat-raised-button color="primary" (click)="onSave()">保存</button> <button type="button" mat-button mat-dialog-close>关闭</button> </div> </form> <mat-autocomplete #autoMembers="matAutocomplete" [displayWith]="displayUser"> <mat-option *ngFor="let item of items" [value]="item"> {{item.name}} </mat-option> </mat-autocomplete>
如果有些情况,希望<mat-option>的value显示的是item,但是希望input中显示的是item的name,或者显示的是另一个组件,或者是一个icon之类的,这种情况可以用displayWith指令,
让[displayWith]="displayFn"函数。
displayWith传入一个函数,指明Input中具体怎样显示.
displayFn(user?: User): string | undefined { return user ? user.name : undefined; }
9、menu
弹出菜单,包括两部分。
一部分是它的触发者,通常是按钮,或者右键点击时候调出菜单。实现的时候就是用matMenuTriggerFor指令,指向menu引用。
第二部分,菜单和菜单项。
<button mat-button [matMenuTriggerFor]="menu">Menu</button> <mat-menu #menu="matMenu"> <button mat-menu-item>Item 1</button> <button mat-menu-item>Item 2</button> </mat-menu>
10、复选框,单选组件和下拉框
几种和HTML对应组件非常像的Material组件:<mat-checkbox>和<mat-radio>和<mat-select>
checkbox还要chenged事件处理
<mat-checkbox [checked]="item.completed" class="status"> </mat-checkbox>
<div class="content" mat-line [ngClass]="{'completed':item.completed}"> <span [matTooltip]="item.desc">{{item.desc}}</span> </div>
Radio Button 为一组数据而存在,数据量少,减少点击用radio。
<mat-radio-group> <mat-radio-button *ngFor="let priority of priorities" [value]="priority.value">{{priority.label}} </mat-radio-button> </mat-radio-group>
select 一组数据而存在,数据量大用select。
<mat-select placeholder="请选择目标列表"> <mat-option *ngFor="let list of lists" [value]="list"> {{list.name}} </mat-option> </mat-select>
11、DatePicker
https://material.angular.io/components/datepicker/overview
两个组件配合使用,[matDatepicker]="picker"让datepicker选中的结果在input中显示。
toggle用matSuffix把toggle作为input的后缀,toggle触发调起datepicker。
<mat-form-field> <input matInput [matDatepicker]="picker" placeholder="Choose a date"> <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle> <mat-datepicker #picker></mat-datepicker> </mat-form-field>
12,tabs
https://material.angular.io/components/tabs/overview
一个mat-tab-group里面套多个mat-tab。
<mat-tab-group> <mat-tab label="First"> Content 1 </mat-tab> <mat-tab label="Second"> Content 2 </mat-tab> <mat-tab label="Third"> Content 3 </mat-tab> </mat-tab-group>
如果觉得本文对您有帮助~可以
微信支持一下: