欢迎各位兄弟 发布技术文章
这里的技术是共享的
1)确保安装了 nodejs
2)
# npm install @angular/cli --global
用它在本地创建一个 Angular 项目,
# cd Desktop/
# ng new ninghao-angular #会有提示询问是否带上路由功能,使用什么css(比如css sass等) 这个命令里面有 npm install功能,但是老是提示 npm install 安装不成功,我执行yarn 安装吧,使用yarn 见 /node-admin/18340 /node-admin/18338 /node-admin/18339 /node-admin/14818 (# ng new ninghao-angular --routing # 如果加上 --routing 表示直接同时带上routing功能了 )
# npm install -g yarn
# yarn config set registry https://registry.npm.taobao.org --global
# yarn config set disturl https://npm.taobao.org/dist --global
# yarn
# ng new ninghao-angular #再执行一下 ng new ninghao-angular 吧
# cd ninghao-angular
# ng serve (ng run start) #package.json中定义,是启动本地的类似于apache的服务
//下面三个语句是实现同样的功能
# yarn add @angular/material @angular/cdk @angular/animations #使用它吧,不用npm了
# npm install --save @angular/material @angular/cdk @angular/animations hammerjs #不用它了
# ng add @angular/material #相当于执行上面的两个命令吧,,,该 ng add 命令将安装 Angular Material、组件开发工具包(CDK)、Angular 动画,并询问一些问题,可以看看 https://material.angular.cn/guide/getting-started https://material.angular.cn/guide/schematics
# yarn add hammerjs #使用它吧,不用npm了,,hammerjs是支持手机的js的触屏功能 angular9之后,已经移除对 hammerjs 的相依,也就不需要另外装了。
main.ts 的顶部加上 import 'hammerjs';
# npm install --save hammerjs #不用它了
在styles.css文件中添加以下条目以获得主题。@import "~@angular/material/prebuilt-themes/indigo-pink.css";
在index.htm文件中添加以下条目以获得 material 图标支持。<link href = "https://fonts.googleapis.com/icon?family=Material+Icons" rel = "stylesheet">
# yarn add web-animations-js # 安装web-animations-js, 接着打开src/pollyills.ts档案,找到import 'web-animations-js'这一行,并且把它取消注解掉,如果找不到这一行,也可以直接手动加入就好。
# ng generate module shared/sharedMaterial --module app #生成一个共享模块,这个模块属于 app 模块
# npm i --save @angular/material-moment-adapter moment #安装material-moment-adapter
来自 https://ithelp.ithome.com.tw/users/20020617/ironman/1263
从Angular第2版正式release后,根据全球最大工程师讨论区StackOverflow的统计,从2016开始的Angular讨论度就不断窜升,甚至超越了React,直到了2017年,甚至摆脱了前一代Angularjs的阴影,跃升成为最热门的前端议题!可以见得Angular这个前端框架确实具有它值得学习的地方,而在2017年底Angular正式迈向第5版,隔天Angular Material就从breaking changes不断的beta版正式升到趋于稳定的rc版,没几个礼拜就直接正式release了!
一个是由Google推出的前端框架,一个是由Google推出的设计语言的Angular实作,两者结合想必能加乘产生N倍以上的爆发力!接下来的日子,我们将一步一步地学会所有Angular Material的元件及特性、Angular CDK及一些进阶的技巧,今天第一天就让我们以比较轻松的节奏来认识所有的基础知识吧!
图片来源:StackOverflow
Angular是由Google推出的前端框架,其热门程度在前端领域的不用多说,占有了非常重要的一席之地,有别于着重在view上的React或Vue这类library,Angular本身就是一个完整的MVC框架!由于整合了大部分前端常用的套件,开发人员只需要着重在学习如何使用Angular这个架构即可,对于刚入门前端或是由后端转前端的人来说大幅降低了学习的曲线,如果本身已经有MVC架构的基本概念,学习上更是如虎添翼。
搭配Angular CLI,开发人员能够以更简单的方式产生一个基本的专案范本,同时只要下一些简单的指令即可产生基本的程式码架构;随着Angular CLI逐渐的进步,开发的弹性也越来越高,例如@angular-devkit/schematics可以让我们在团队中建立共用的范本程式等等,让开发速度大耀进!
Angular主要以TypeScript作为开发语言,TypeScript是JavaScript的超集合,能让我们在开发JavaScript时能以强型别的方式撰写程式,并在转译成JavaScript时自动检查型别的错误,减少runtime时的debug成本;同时TypeScript能让我们不断享受使用最新的语法来撰写程式的快感,只需要稍作设定即可把最新的语法转为比较旧的语法,避免浏览器支援度的问题!也由于Angular开了这一枪,让各种热门的前端library/framework也陆陆续续有了TypeScript开发的版本,足见TypeScript对于前端世界的影响力也将越来越高!
由于本系列文章属于稍微进阶的Angular议题,因此对于Angular基础的知识将不会有太多的介绍,建议读者至少具备以下Angular基础后,在阅读本系列文章:
了解Angular的MVC架构
使用Angular CLI建立专案并开始开发
懂得如何设计并共用一个component
理解最基本的Angular相依注入的知识,并能实作一个service注入到component之中
有基本的模组化概念
能设定router完成SPA程式
就算没有以上的知识,也完全不用担心,网路上也有很多的参考资源,甚至还有中文版的文件,只要愿意花个几天时间,要对Angular有基本的认绝对不会是个问题!
当然,如果你有更多前端的相关知识如node、webpack等等,对于学习Angular或Angular Material绝对是加分的要素。
Material Design是由Google推出的设计语言,也可以把它想像成是一种设计的pattern,把视觉化设计的概念、网页元件、操作互动等等理论及实作整理出来的设计准则,从元件的配色、阴影到特效都有一定的规则可循,我们能透过这些准则设计出清楚明确且容易使用的使用者介面(UI),打造更好的使用者经验(UX);如果你是Google相关服务的爱用者,又对Material Design有点了解,相信你一定也有发现Google的各种服务在设计上也已经不断朝Material Design迈进了。
由于Material Design仅仅只是一种设计的准则,不像bootstrap这类css framewrok,有直接的css样式或javascript library可用,而是交由设计人员依照准则进行实作,偏偏Material Design的设计准则又非常多,一般开发人员不可能有时间依照这些准则一一设计,好在也有许依照Material Design的设计准则开发且open source的专案可用。例如Google官方推出的Material Design Lite和多平台都支援的
Material Components,或是由4个亚洲人合力开发出来的Materialize.css等等,都是目前常见的Material Desig实作版本。
当然像是React或Vue这类热门的前端框架也很容易能够找到相关的设计套件,透过这些实作套件,即使是没有美感的前端工程师也能够轻易设计出简单大方,又不失设计感的页面。
而身为爸爸同样是Google的Angular,有一套由官方推出的Material Design套件也不是件奇特的事情,也就是接下来要介绍的Angular Material。
Angular身为Google自家推出的主力前端框架,而Material Design又是Google未来设计的主要方向,自然而然的,也免不了要替Angular量身打造一套Material Design的套件,也就是本系列的主轴-Angular Mateial 。
根据Angular Material官方的说法,Angular Material的目标是使用Angular及TypeScript打造出高品质的UI元件,同时这些元件必须遵守Material Design的设计标准。
所谓的高品质,对于Angular Material来说包含了以下几个重点:
i18n及a11y:所有Angular Material提供的元件原则上都不会有无法支援多语系的情况,且同时也都能够可存取性(a11y)的开发,让所有使用者都能够轻易与这些元件互动。
直觉的API
在大部分通用的情况下,是不会有bug的
所有的元件都有撰写良好的单元测试及整合测试
可以依照Material Design准则客制化这些元件的细节
高效能
干净的程式码且所有元件都有清楚的文件及范例
从上段介绍可以看到,Angular Material对于品质的要求,从程式码本身到元件实用性都完全顾虑到了,如果能够达到这样的品质,绝对可以说是目前其他任何Material Deesign套件所望成莫及的程度!也因此不难想像在beta时期,Angular Material可以说是不断的breaking change,想必就是为了能够不断的往所谓**「高品质」的目标迈进,这也成了很多想要进入Angular Material世界的人裹足不前的理由;尽管骂声不断,但朝着目标迈进的Angular Material在不断进化的Angular推出第5版后,Angular Material的版本也从2.0.0-beta一下子大跃进为5.0.0-rc* *!同时才几个礼拜后的2017/12/06迈入正式版,在这个刚release的时候进入学习既能避免不断breaking changes的伤害,又能够跟别人炫耀 赢在起跑点,实在是个很不错的进入时机!这也成了这次铁人赛想要以Angular Material为目标的主要原因!
本系列的文章将会以Angular Material的官方文件为主要依据,一步一步带领读者们学习利用目前(5.0.0)所有的元件(共30个)来打造一个具备设计质感后台网站(dsahboard),并完成一些简单的页面,并会进一步介绍功能强大好用的Angular CDK,时间允许的话,再介绍一些关于Angular Material的进阶技巧!初步的规划有如下3个单元:
完全掌握Angular Material (约20天):这段时间会介绍所有的Angular Material元件,并穿插在不同功能之中,除了设计一个基本的后台架构以外,也会设计出简单的问卷表单、部落格和邮件收件夹的画面,让读者能对所有的Angular Material元件都能够有一定的掌握度,并懂得如何依照需求变化出不同的呈现方式。这个单元会切成5个子单元,分别是基础篇、Dashboard篇、问卷表单篇、部落格篇和收件夹篇。
介绍Angular CDK (约5~10天):Angular CDK(Component Development Kit)是Angular Material在设计元件时拉出来的共用程式,用来解决许多元件设计上的问题,帮助开发人员即使不使用Material Design,也能够透过Angular CDK设计出高品质的元件或互动功能,元件开发工具(Component Development Kit)这个词实在是当之无愧!在这单元中我们会透过Angular CDK来解决一些上个单元后台网站不足的部分,让整个网站更加的丰富。
进阶的Angular Material开发技巧 (约5天,状况允许的话能多写就多写):介绍一些客制化Angular Material的方式,除了直接使用Angular Material提供的元件以外,要让网站具有Material Design的设计质感还有很多的方式,也会在这个单元一并介绍。
之后的程式码将会统一放在GitHub上,并以天为单位建立分支(day-02, day-03, ...ect),方便大家随时切换到每一天的记录去了解程式码的变化,相信对于学习会更有帮助。
关于这系列的文章,是笔者个人对于Angular Material及Angular CDK研究后的整理,希望能帮助读者更容易进入Angular Material的世界,如果有任何问题,欢迎随时在留言提出讨论,彼此学习,互相成长;若发现有任何词句不顺、错别字、或是观念错误等等,也一样欢迎提出来,让整个系列文章的完整度更高!帮助更多人进入这个美妙的世界!!
今天的文章目标主要是让大家对于Angular、Material Design及Angular Material有个初步的理解,Material Design本身是个非常棒的设计概念,以笔者有限的能力可能无法很完成的将精髓传达给每个人,建议大家有空可以直接多去看看Material Design的设计风格,时间允许的话也可以大致浏览一下Material Design的设计准则,对于之后学习Angular Material开发时会更加的有感觉!
明天开始就让我们前往高质感的前端设计之路迈进吧!!
这次的铁人赛很特别,虽然早就有参赛的打算,但对于这次新的玩法團體賽
可以说是从来没想过,收到Alan Liu哥邀请的时候,实在是受宠若惊XD;也因为加入了团队,在赛前的讨论也让这次的参赛更加不寂寞,一群人相约在同一时间发文,并在群组内互相加油打气(甚至定下惩罚条款XD),感觉实在是很好^^
希望未来的铁人赛也能继续加入这个制度,让彼此在学习这条路上不寂寞。
以下是这次参赛的团员,按照2018新年快乐团队介绍的顺序排列,欢迎大家订阅他们的系列文章,给他们加油打气!
团长Alan Tsai Data Science到底是什么-从一个完全外行角度来看
Wellwind Angular Material完全攻略
Duran Hsieh SQL Server学习日志
gary_lin React.js & Laravel 30天训练
superpucy 从工程师的角度看UX/UI
alan.liu Learn Azuer in 30 days
rabbitlai 工程师职灾的认识与预防
bymiachang Data Science with Azure
900pro 在Mac上开发.Net Core
本文章同步发表于: https://wellwind.idv.tw/blog/2017/12/19/angular-material-01-intro/
来自 https://ithelp.ithome.com.tw/articles/10192187
今天我们将开始正式迈入Angular Material的世界,要学习使用Angular Material打造高品质及高质感的网页,当然要从安装Angular Material套件开始,本篇文章就来介绍基本的Angular Material安装步骤,并简单加入一个元件来体验一下有质感是怎样的一个感觉!
本篇文章需要在电脑上安装node.js,并透过npm安装相关的套件(或是你想用yarn也没有问题),同时,你也必须安装Angular CLI。
虽然本系列文章假设读者已经有基本的Angular知识及会使用Angular CLI,但还是简单说明一下安装Angular CLI的方式(毕竟不是每个开发人员都会去使用Angular CLI来建立程式,只是使用Angular CLI比较方便而已),透过npm安装Angular CLI很简单,只要简单一行指令就可以了
npm install -g @angular/cli
再写这篇文章时,笔者的电脑中使用的Angular CLI版本为1.6.0。
使用Angular CLI来建立新的专案也是简单到不行,使用ng new
指令一行搞定:
ng new it-ironman-demo-angular-material --routing
由于之后还要开发其他的页面,所以加上了--routing
,这会在专案中增加一个app-routing.module.ts
的档案,方便未来增加模组以及页面连结时作设定。
接下来我们就要正式把Angular Material相关的套件装进来并且进行设定啦!
首先第一步我们先把套件装进来再说,进入专案目录(以上面的例子来说专案目录是it-ironman-demo-angular-material
)
npm install --save @angular/material @angular/cdk
如果你喜欢尝鲜,也可以安装最新非稳定的版本,Angular Material也提供了一个snapshot build,当然这不建议在真正的production环境上使用。
npm install --save angular/material2-builds angular/cdk-builds
Angular Material运用了不少动画特效来让元件显示更加生动,这都多亏了@angular/animations这个套件,如果希望能在页面上看到这些动画效果,需要安装@angular/animations:
npm install --save @angular/animations
接着在我们的AppModule中的imports里面加入BrowserAnimationsModule
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@NgModule({
...
imports: [
...
BrowserAnimationsModule
],
...
})
export class AppModule { }
虽然动画效果会让画面更加丰富,但也有可能会有效能问题,且不是每个人都喜欢那么多的特效,想要取消特效的话,可以改加入NoopAnimationsModule
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
@NgModule({
...
imports: [
...
NoopAnimationsModule
],
...
})
export class AppModule { }
@angular/animations使用了WebAnimation API,但不是所有浏览器都有支援,如果你希望尽可能让所有浏览器都支援,可以安装web-animations.js
套件。
npm install --save web-animations-js
接着打开src/pollyills.ts
档案,找到import 'web-animations-js'
这一行,并且把它取消注解掉,如果找不到这一行,也可以直接手动加入就好。
Angular Material将所有的主要元件都都方入对应的模组之中( MatXXXModule
),让我们只有需要使用到某一群元件时,汇入相关模组就好,避免汇入过多不必要的元件。
假如我们要使用Angular Material的button特性,可以汇入MatButtonModule
import { MatButtonModule } from '@angular/material';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@NgModule({
...
imports: [
...
BrowserAnimationsModule,
MatButtonModule
],
...
})
export class AppModule {}
另外一种方式是**,建立一个SharedModule,将常用的MatXXXModule先import,再export出来**,在其他Module中就只要import这个SharedModule就好,这在较复杂的SPA程式中会非常实用。当然这个SharedModule只是个概念,实际上我们可以用这个概念分类出不同的Modules,例如专门放常用的Angular Material Components的Module我们就取名叫做SharedMaterialModule吧!
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material';
@NgModule({
imports: [MatButtonModule], // 先import
exports: [MatButtonModule] // 在export
})
export class SharedMaterialModule {}
如果Module里面没有其他需要使用到Angular Material的元件,也可以直接export就好
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material';
@NgModule({
exports: [MatButtonModule] // 直接export
})
export class SharedMaterialModule {}
然后在使用到的Module中汇入即可,唯一要注意的是,这个SharedMaterialModule一定要放在BrowserModule之后!
import { SharedMaterialModule } from './shared-material/shared-material.module';
@NgModule({
...
imports: [
BrowserModule,
...
SharedMaterialModule
],
...
})
export class AppModule {}
关于SharedModule的概念,可以参考官方文件的介绍。
Material Design是极具质感的设计样式,因此Angular Material自然也少不了基本的CSS样式,目前(5.0.0-rc)Angular Material包含了4种内建的样式,在@angular/material/prebuilt-themes/
,可以找到这4个css档。
另外这4个布景的样式也可以再Angular Material官方文件首页的上半部作切换
以下是这4个样式在官方首页的样式,提供参考
indigo-pink.css
deeppurple-amber.css
pink-bluegrey.css
purple-green.css
未来Angular Material也会持续增加不同的配色;当然,我们也可以自己设计自己想要的样式,在Angular Material要产生客制化的样式非常简单,只需要简单设定要搭配的颜色即可,在后续的文章会介绍如何自订自己的Angular Material Theme。在这里我们只要先选择内建的theme就好,我们可以把这个theme的css加到styles.css中。
@import "~@angular/material/prebuilt-themes/indigo-pink.css";
之后用到的Angular Material元件就会自动套上这样的样式啰。
在某些元件中,会依照浏览的装置不同而有不同的互动,例如tooltip在一般PC上只要滑鼠游标移过去就会显示,但在行动装置中,则需要长按才会出现,这部分Angular Material搭配了HammerJS,为UI加上行动装置的手势支援,如果开发的网页需要在行动装置上也能达到最好的体验,就必须在程式中载入HammerJS。
有万能的npm,这些套件都只是一行指令的问题而已
npm install --save hammerjs
安装完HammerJS后,还需要在程式中载入,我们可以直接在程式的进入点src/main.ts中加入
import 'hammerjs';
Material Icons是搭配Material Design出来的一系列icon set,在Angular Material中,我们也可以透过MatIcon来统一显示icon的逻辑,以现代化网页设计来说,想要使用Material Icons最简单的方式,就是直接在index.html中加入相关Icon Font的CDN:
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
上述的步骤已经把所有Angular Material相关的套件及设定都完成了,同时我们也练习载入了MatButtonModule,既然都已经载入了,我们就直接来写一个Button来看看吧!
在app.component.html中先写一个简单到不行的button
<button>Hello World!</button>
这时候的按钮随著作业系统、浏览器的不同会有不同的显示方式。接着我们来让它变成一个充满Material Design样式的按钮吧!
在Angular Material中使用了原生的按钮,但是加上了directive让按钮有了Material Design的样式,最简单的directive就是mat-button
<button mat-button>Hello World!</button>
来看看结果:
可以看到整个按钮的样式变得不一样了,同时点选下去也有清楚的wave特效,这让我们的按钮从此活了起来!画面更加丰富!!
在之后的文章我们会在对MatButton有更熟悉的理解,不过在这里我们还是手痒稍微修改一下按钮的样式,让按钮能有不一样的呈现方式
<button mat-raised-button color="primary">Hello World!</button>
我们改用了mat-raised-button,让按钮变成有有层次的阴影,同时加上color="primary"
,为按钮加上了主题色的主要颜色,看看结果:
可以发现按钮变成了蓝色的背景,而且也有了些阴影,这可以让画面更佳的有立体感,颜色也更加鲜明;在所有的Angular Material的元件都有类似的立体效果及配色,让整个画面呈现能够更加的层次分明,是不是对于Material Design的设计有了更多的期待啦!
如果有使用SystemJS的方式载入模组,官方文件也有说明该如何使用,可以参考看看
https://material.angular.io/guide/getting-started#appendix-configuring-systemjs
如果你已经迫不及待要去Angular Material的文件上看看有什么好玩的元件可以用了,在这边做一点小提醒,由于文件目前还没有完全更新,有些程式码可能会是错的,最主要的部分是当看到mdXxxx
或md-xxxx
时,都是旧版的写法,Angular Material 5之后统一都改成matXxxx
或mat-xxxx
的写法,因此当你复制程式时,别忘了看一下是不是旧版的写法,可能会导致跑不出结果喔!
今天我们介绍了将Angular Material加入Angular专案的方法,虽然不算复杂,但也有些细节需要注意,并且也理解到Angular Material需要相依一些套件,才能发挥出全部的威力,尽管没有这些相依套件,也不会影响到主要的操作,但如果可以的话,还是建议把这些套件都加进来,让前端画面能够更加丰富!
安装完Angular Material后,我们也实际用按钮当作案例,建立了一个充满Material Design风格的按钮元件,让按钮不再是死板板的按钮,还要担心作业系统和浏览器不同而有不同的显示方式,让呈现更加一致,也更加的生动。
明天即将开始进入正戏,介绍Angular Material的元件啦!
本日的程式码GitHub:https://github.com/wellwind/it-ironman-demo-angular-material/tree/day-02-prepare-installation (分枝:day-02-prepare-installation)
本文章同步发表于: https://wellwind.idv.tw/blog/2017/12/20/angular-material-02-installation/
应该是styles.css才是
感谢回馈,已修改
大大您好:
您在加入Angular Material Theme有用到~
来套用样式,想先请问~
的功能是什么?
@import "~@angular/material/prebuilt-themes/indigo-pink.css";
而我在套用Material Icons时使用~
,这样会不会找不到路径?
@import "~material-design-icons/iconfont/material-icons.css";
我有先用ng serve 试过,可以在网页上出现icon 图示。只是不知道用ng build 后会不会发生问题。
~
代表的是去node_modules
去寻找是否有安装对应的套件,有的话就把套件目录下指定的位置内容加进来
来自 https://ithelp.ithome.com.tw/articles/10192517
今天是第一天正式介绍Angular Material的相关元件,就让我们先从比较简单轻松的Icon来开始,虽然说是比较简单轻松,但其实里面也是有不少学问的,透过今天的介绍,你会发现其实Angular Material提供的Icon元件也是非常强大的!
在Material Design这套设计语言里面,将Icon分成两类-产品Icon(Product Icon)和系统Icon(System Icon),Product Icon象征着产品或服务的最主要门面,而System Icon则是系统或服务里面的操作行为的识别。
关于Icon的设计,其实是有非常多学问在里面的,毕竟这会影响着一只程式的识别度,好的Icon可以让人轻松把你的产品跟Icon连结在一起,不好的Icon只会让人遗忘掉产品的存在,而Material Design在产品Icon的设计上面,给了非常多的建议,不过我们毕竟不是视觉设计师,而是前端开发人员,而且产品Icon也不是Angular Material的重点,就不多作介绍,有兴趣的朋友可以去看看Material Design对于产品Icon的设计哲学跟建议,对于要设计产品Icon的朋友应该会很有帮助。
身为前端开发人员,我们可能没有办法过度的深入产品Icon的设计,但在前端操作上我们则有着很大的生杀大权(?),尤其在不是以设计美感为主的后台程式或是新的产品需要一个快速的概念验证时,前端人员对于画面的掌控性就相对大很多,而画面上的各种操作,有时候只需要一个简单的Icon就可以说明一切,例如我们只需要看到如下磁片的图示,就知道这代表着"存档"的意思
这种系统Icon对于前端的UI来说就至关重要,有时候一个好的系统Icon可以完整的说明系统的行为或状态,而不好的Icon加上没有适当的说明,就会让操作变得更不流畅;只要有了适当的Icon,平凡的网页就立刻有的不凡的生命力,可以说是现代化网页设计非常重要的一个环节啊!而关于系统Icon,在Google官方也推出了一系列超过900个系统Icons,提供给大家使用,也就是Material Icons。
分享一个网路上看到的有趣图片,说明了磁片时代的眼泪,过去的存放资料的重要媒介,如今也只不过是个最常见的存档Icon而已了,虽然一样都很重要,但认知上已有了极大的落差。
图片来源:https://twitter.com/mymemory/status/766244541628284929
Google本身已经提供了超过900个系统Icons,而且完全Open Source,要用这些Icon本身很简单,如果在前一天安装Angular Material时有做最后一步骤加入Material Icons的CDN,就已经具备了使用Material Icons的条件,我们可以在Material Icons官网上方的Search搜寻框中输入想要使用的icon, 就可以找到使用这个icon所需要的使用的语法
例如我想要寻找跟人有关的icon,可以在搜寻框中输入person
,即可看到跟person有关的icons
接着点击想要放到网页上的icon,下方就会显示可以加入网页的方法,例如下载SVG或PNG档,或是使用我们接下来要介绍的Icon Font的方式:
如果看到想要加入一个人的图像,可以使用以下语法
<i class="material-icons">person</i>
我们只需要直接在程式中加入这段语法,就能够轻易的将icon加到画面上啦!
有了基本的Material Icon概念和了解系统Icon的使用方法,接下来我们就来看看Angular Material中对于使用Icon还能有些什么灵活的变化吧!!
使用<i class="material-icons">person</i>
的方式来显示Material Icon本身已经是一件很容易的事情,但对于像Angular这种以元件的方式来开发的情境上,这种HTML Tag就略显得不够语意化,因此Angular Material在显示Icon上另外提供了一个元件,也就是MatIcon。
要使用MatIcon,首先必须加入MatIconModule到你的目前使用的Module里面:
import { MatIconModule } from '@angular/material';
@NgModule({
...
imports: [
...,
MatIconModule],
...
})
export class AppModule {}
而MatIcon的基本语法很简单:
<mat-icon>person</mat-icon>
中间的person
一样是Material Icons里面可以选的icon名称,不同的是外面由<mat-icon>
这个元件标签包起来;虽然效果是完全一样的,但比起原来必须看到class="material-icons"
才知道使用的是Material Icon,现在只要看到<mat-icon>
就知道了,同时以Angular Material为基础设计出来的元件,也能够有比较多的Material Design相关变化。
例如预设的MatIcon会是我们加入的theme的文字颜色(currentColor),但我们可以很容易的透过color
属性,来切换icon的颜色类型。
未来我们加入Angular Material相关的Module,除非特别说明否则都会在
@angular/material
中。
在Material Design的System Color指南中,建议配色的选择为两种主要颜色(primary color) 跟次要颜色(secondary color),用来区分主要的功能颜色及强调可以选择的画面,另外在表单相关的元件上还加上了错误讯息(error message)的颜色,而在Angular Material的样式中将这三种颜色名称分别订为primary
、accent
和warn
。
在大部分的Angular Material提供的元件中,我们都可以透过color来切换这三种颜色,以MatIcon为例
<div>
這是一般的ICON顏色
<mat-icon>person</mat-icon>
</div>
<div>
這是加上primary顏色的ICON
<mat-icon color="primary">thumb_up</mat-icon>
</div>
<div>
這是加上accent顏色的ICON
<mat-icon color="accent">info</mat-icon>
</div>
<div>
這是加上warn顏色的ICON
<mat-icon color="warn">warning</mat-icon>
</div>
结果如下图:
当然我们还是可以透过设定css来切换成不同的颜色,不过在设计上这种事情则需要尽量避免,在Material Design的建议中,除了文字颜色和背景颜色以外,主要就这三种颜色了,适当的搭配使用这三种颜色,可以让画面不至发生于颜色大爆炸,也能保持简单大方的设计样式,让使用者在操作时也不容易被颜色搞混,可以说是很重要的观念!
MatIcon除了能够直接使用Material Icon以外,我们还能够过MatIconRegistry来扩充能够使用的Icons;MatIconRegistry具有两个功能,一个是直接在MatIcon中加入SVG图档,另外一个则是支援使用其他的Icon Font,这在我们所需要的Icon超出Material Icon提供的范围时非常实用,同时又能保持使用一致的MatIcon元件来显示画面。
在这边我们使用颜色单纯的SVG图片作为范例,图片来源来自Angular官方网站的Press Kit:
先将这张图片下载到我们专案目录的src/asset/imges资料夹中
接着注入MatIconRegistery
及DomSanitizer
,由于SVG icon是在程式中透过路径载入,为了避免XSS的问题,必须透过Angular提供的DomSanitizer service来信任这个路径,如果你的图片放在网路上的其他来源,同时还需要注意cors的问题,不过这已经超出这次介绍的范围,就不多做说明。
import { Component, OnInit } from '@angular/core';
import { MatIconRegistry } from '@angular/material';
import { DomSanitizer } from '@angular/platform-browser';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
title = 'app';
constructor(private matIconRegistry: MatIconRegistry, private domSanitizer: DomSanitizer) {}
ngOnInit() {}
}
另外为了能够在程式中下载这张图片扩充为我们的icon,还需要再加入HttpClientModule
,加入方法也已经是基本知识,就不多说明啰。
接着我们就可以透过MatRegistery
来扩充SVG icon啦! 下面的代码放在ngOnit()里面不能显示图标,只能放在 construct()里面,不知道什么原因
this.matIconRegistry.addSvgIconInNamespace(
'custom-svg',
'angular',
this.domSanitizer.bypassSecurityTrustResourceUrl('assets/images/angular_solidBlack.svg'));
MatIconRegistery.addSvgIconInNamespace有三个参数:
namespace:icon的namespace,方便用来分类不同的icons,也能够避免名称冲突
iconName:给予这个icon一个名称
url:一个安全的图片来源
加入这个设定后,我们就可以直接在画面中使用这个icon啦!更棒的是,只要svg icon里面没有特别设定任何颜色的话,我们还能够过color
属性来直接调整我们的svg icon的颜色!
加入svg icon可以透过MatIcon的svgIcon
属性来设定,必须依照[namespace]:[iconName]
的方式来指定:
<h2>自行註冊SVG icon</h2>
<div>
<mat-icon svgIcon="custom-svg:angular"></mat-icon>
<mat-icon svgIcon="custom-svg:angular" color="primary"></mat-icon>
<mat-icon svgIcon="custom-svg:angular" color="accent"></mat-icon>
<mat-icon svgIcon="custom-svg:angular" color="warn"></mat-icon>
</div>
结果如下:
除了自订svg icon以外,网路上也有许多现成的icon font可以使用,例如知名的FontAwesome、IonIcons等等,使用方式基本上大同小异,而我们也能够很轻易的将这些icon font纳入MatIcon之中,让画面上的程式码更加一致!
以FontAwesome为例,我们可以先在index.html
中加入FontAwesome的CDN:
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
在写这系列文章前没多久FontAwesome其实刚升上第5版,但使用上会稍有不同,为了教学方便,还是使用第4版做范例,不过纳入
MatIcon
的方式是完全一样的。
接着一样可以透过MatIconRegistery
的方式加入
this.matIconRegistry.registerFontClassAlias('fontawesome', 'fa');
MatIconRegistery.registerFontClassAlias有两个参数:
alias:原来icon font class的别名,例如FontAwesome都会在class里面加上fa
之后才加上fa-*
,这里要设定的就是fa
的别名。
className:原来icon font的主要class,以FontAwesome来说也就是fa
接着我们就可以使用MatIcon来显示FontAwesome,同时享受MatIcon的功能啦!
使用Icon Font需要设定两个属性,分别是fontSet
代表刚才注册的alias,以及fontIcon
代表真正要使用的icon class。
<h2>在MatIcon中使用FontAwesome</h2>
<div>
<!-- 就是<i class="fa fa-thumbs-up">的概念 -->
<mat-icon fontSet="fontawesome" fontIcon="fa-thumbs-up"></mat-icon>
<mat-icon fontSet="fontawesome" fontIcon="fa-thumbs-up" color="primary"></mat-icon>
<mat-icon fontSet="fontawesome" fontIcon="fa-thumbs-up" color="accent"></mat-icon>
<mat-icon fontSet="fontawesome" fontIcon="fa-thumbs-up" color="warn"></mat-icon>
</div>
成果如下:
小提示1:FontAwesome提供了许多除了显示icon以外的class,例如让icon旋转的
fa-spin
等等,我们一样可以透过class="fa-spin"
的方式加入。小提示2:使用这种方式虽然具有一致性的效果,不过对于开发来说则未必是好事,尤是我们常常仰赖工具的code snippets时,这种语法反而会阻碍了我们原来的习惯,至于该如何选择就看个人喜好啰。
今天我们认识了Material Design中的Icon设计哲学,以及身为前端开发人员最常使用的系统Icon使用方式,学到了Material Icon的使用方式。
而在Angular Material中我们能够透过MatIcon来帮助我们统一管理这些icons,让view上的语法呈现更加一致明确。
同时我们也简单认识了Material Desing基本的配色概念,以及了解到Angular Material中使用这些颜色的方式。
MatIcon本身的能力也超过了Material Icon的范围,除了用来产生现有的Material Icons以外,我们也能自行加入SVG图档来当作icon显示,更方便的是我们还能把其他网路上知名的Icon Font样式一并套进来,通通使用MatIcon的方式进行管理,非常的方便及强大。
适度地替系统加上Icon能达到画面更简洁,但操作却更清楚的效果,把这些使用方式都学会,就能轻易的在画面上加入各种的icons啦!
本日的程式码GitHub:https://github.com/wellwind/it-ironman-demo-angular-material/tree/day-03-mat-icon
分支:day-03-mat-icon
本文章同步发表于: https://wellwind.idv.tw/blog/2017/12/21/angular-material-03-icon/
下载***者***张图片
我们能够***过***MatIcon来帮助我们
已修正,感谢您的回馈^^
来自 https://ithelp.ithome.com.tw/articles/10192806
今天我们要来介绍Angular Material按钮(button)的使用方法,按钮可以说是一切互动介面的基本,只要按下了按钮,所有事情都可能会发生,也因此设计良好的按钮是非常重要的,除了让事情发生外,也要让使用者能够明确的知道按钮背后的意义,今天就让我们看看Material Design中按钮的设计思维,以及如何在Angular Material如何轻易地达到这些设计的目标吧!
在Material Design的Button的设计指南中,按钮主要分为3种类型:
扁平化按钮(Flat Button):一个基本的文字矩形,通常使用在dialog、toolbar之中,颜色很简单,在不是以按钮为主的元件中这些按钮扮演着配角的角色,让你不会过度的注意它,但在需要时又能明显知道它的存在
凸起的按钮(Raised Button):具有阴影且明显的按钮,在画面上会比较有立体感、甚至是一个明显的色块,会跟其他扁平化的元素产生不同空间的感觉,因此在视觉上会非常具有存在感,适合用在需要提醒使用者按下的地方,例如加入购物车这种的按钮就很适合使用。
浮动的动作按钮(Floating Action Button):Floating Action Button是Material Design中非常重要且独特的一种设计方式,重要到在官方的设计指南中有独立的一个完整篇章在介绍它,它通常会固定在整个萤幕或是某个功能区快的固定位置,用来提醒使用者这个按钮具有(或包含)画面上最常使用到的功能,也可以想像成是一种捷径的概念。为了凸显这种按钮的存在,又要避免存在有着突兀的感觉,因此会设计成圆形但不会太占空间的按钮,也因此基本上按钮中只会放置Icon,比较少会放文字。
除了扁平化的按钮是为了在画面上有协调的感觉以外,其他的按钮设计都是为了凸显自身的存在,因此在设计上也都会呈现阴影的感觉,让视觉上更加清楚。
在Angular Material中,所有的按钮都放置在MatButtonModule中,因此使用时记得加入这个Module
import { MatButtonModule } from '@angular/material';
@NgModule({
...
imports: [
...,
MatButtonModule],
...
})
export class AppModule {}
由于按钮在网页上的存在极具意义,Angular Material在设计上并未把按钮封装成component,而是以directive的方式附着在<button>
或<a>
标签上,并透过样式的变化让原来的<button>
或<a>
标签具有Material Design的风格。
扁平化按钮是最基本的按钮样式,使用上非常简单,在原来的button或a标签上加上mat-button
即可
<button mat-button>我是按鈕</button>
这时候在画面上看起来会完全没有按钮的感觉,而只是个文字的存在,但当滑鼠移到按钮上时,则会看到比较深色的背景,按下去时则会产生互动的涟漪效果。
当然,我们也可以使用color
属性来改变按钮的颜色,同时也可以使用disabled
属性禁止按钮被点选。
<button mat-button>我是按鈕</button>
<button mat-button color="primary">Primary</button>
<button mat-button color="accent">Accent</button>
<button mat-button color="warn">Warn</button>
<button mat-button disabled>Disabled</button>
<a mat-button>Link</a> <!-- 放在a tag裡面也沒問題 -->
效果如下:
比起扁平化的按钮,凸起的按钮会有明显的反差,也会有比较深的阴影效果,以凸显按钮的存在,凸起的按钮需要加上mat-raised-button
<button mat-raised-button>我是raised按鈕</button>
<button mat-raised-button color="primary">Primary</button>
<button mat-raised-button color="accent">Accent</button>
<button mat-raised-button color="warn">Warn</button>
<button mat-raised-button disabled>Disabled</button>
<a mat-button>Link</a>
效果如下:
要替按钮加上Icon本身是一件很简单的事情,在标签内加上<mat-icon>
就可以了,例如:
<button mat-raised-button color="primary"><mat-icon>thumb_up</mat-icon> 我有Icon</button>
效果如下:
不过如果我想只想要icon,不要搭配文字呢?
<button mat-raised-button color="primary"><mat-icon>thumb_up</mat-icon></button>
结果:
这样有点问题的是,左右留白太多了好像有点浪费空间,毕竟只想要icon的按钮通常就是为了能够节省空间啊!这时候可以使用专门为了呈现icon的mat-icon-button
来解决这个问题:
<button mat-icon-button color="primary"><mat-icon>thumb_up</mat-icon></button>
结果:
看起来就单纯许多,如果希望凸显这个按钮,我们可以先用mat-raised-button
将它变成更明显的按钮,在使用mat-icon-button
改变成为左右不留白的样式
<button mat-raised-button mat-icon-button color="primary"><mat-icon>thumb_up</mat-icon></button>
结果:
可以看到按钮的留白就移除了,边角也变成了圆形的,只有Icon的单一按钮用这样的呈现方式感觉还不错!
接下来要介绍的是预设就是圆形的floating action button,我们使用到mat-fab
这个directive:
<button mat-fab>
<mat-icon>thumb_up</mat-icon>
</button>
<button mat-fab color="primary">
<mat-icon>thumb_up</mat-icon>
</button>
<button mat-fab color="accent">
<mat-icon>thumb_up</mat-icon>
</button>
<button mat-fab color="warn">
<mat-icon>thumb_up</mat-icon>
</button>
<button mat-fab disabled>
<mat-icon>thumb_up</mat-icon>
</button>
效果如下:
可以发现一件事情,在没有指定颜色的时候,mat-fab
的样式与accent颜色是一样的,可以见得floating action button本身的设计理念就是为了凸显它的存在感,这刚好与accent的概念是用来强调这里有东西的颜色概念一样,不得不佩服Angular Material设想得非常周到。
mat-fab
本身应为圆形且要凸显的效果,整个按钮看起来会比较大,但对于比较小的区块中要使用时反而会显得太过突兀,这时候我们也可以使用mat-mini-fab
来产生比较小的floating action button
<button mat-mini-fab>
<mat-icon>thumb_up</mat-icon>
</button>
<button mat-mini-fab color="primary">
<mat-icon>thumb_up</mat-icon>
</button>
<button mat-mini-fab color="accent">
<mat-icon>thumb_up</mat-icon>
</button>
<button mat-mini-fab color="warn">
<mat-icon>thumb_up</mat-icon>
</button>
<button mat-mini-fab disabled>
<mat-icon>thumb_up</mat-icon>
</button>
跟原来的按钮比较效果如下:
mat-mini-fab
产生的按钮样式跟一般的按钮高度就会一样,因此看起来会跟使用mat-raised-button
加上mat-icon-button
的组合技有一样的效果,不过在语义上则是不一样的东西。
以上就是整个Angular Material中的按钮基本用法,并不会非常困难,主要就是几个directives,依照不同的情境决定使用方式;接下来要介绍的是类似按钮却不是按钮的东西,叫做按钮开关(button toggle)。
按钮开关基本上不是按钮,反而比较类似checkbox,偏偏它又不像checkbox是表单控制项,可以搭配ngModel使用,因此单一的按钮开关使用上会比较没有意义,而是使用一个群组式的按钮开关,应用层面比较广
mat-button-toggle
放在MatButtonToggleModule中,使用前记得加入这个Module,加入后我们可以直接在画面上使用
<mat-button-toggle>我是個開關</mat-button-toggle>
结果如下:
可以看到每次点下去,就有切换开关的效果。mat-button-toggle
这个component本身还有如checked、value、disabled
等属性可以使用,我们将在下一个Button Toggle Group中一起混着使用
mat-button-toggle-group
可以放置多个mat-button-toggle
,并且依照被选取的mat-button-toggle来决定自己的值是什么,我们可以设计一个简单的画面如下:
<mat-button-toggle-group #formatAlignGroup="matButtonToggleGroup">
<!-- button toogle所代表的值 -->
<mat-button-toggle value="left">
<mat-icon>format_align_left</mat-icon>
</mat-button-toggle>
<!-- 預設被選取 -->
<mat-button-toggle value="center" checked="true">
<mat-icon>format_align_center</mat-icon>
</mat-button-toggle>
<mat-button-toggle value="right">
<mat-icon>format_align_right</mat-icon>
</mat-button-toggle>
<!-- 不允許選擇的button toggle -->
<mat-button-toggle value="justify" disabled>
<mat-icon>format_align_justify</mat-icon>
</mat-button-toggle>
</mat-button-toggle-group>
<div>對齊方式為:{{ formatAlignGroup.value }}</div>
<!-- 加上multiple,則裡面的mat-buttong-toggle可以複選 -->
<!-- 加上vertical="true", 改變排列方式 -->
<mat-button-toggle-group multiple vertical="true">
<mat-button-toggle value="bold" #buttonToggleBold>
<mat-icon>format_bold</mat-icon>
</mat-button-toggle>
<mat-button-toggle value="italic" checked="true" #buttonToggleItalic>
<mat-icon>format_italic</mat-icon>
</mat-button-toggle>
<mat-button-toggle value="underlined" checked="true" #buttonToggleUnderlined>
<mat-icon>format_underlined</mat-icon>
</mat-button-toggle>
</mat-button-toggle-group>
<div>粗體:{{ buttonToggleBold.checked }}、斜體:{{ buttonToggleItalic.checked }}、底線:{{ buttonToggleUnderlined.checked }}</div>
在上面的程式中,第一段ButtonToggleGroup中我们使用value为每个mat-button-toggle
中设定所属的值,并且设定checked="true"
来设定预设选取的效果、以及disabled
来设定禁止点选,接着透过template reference取得ButtonToggleGroup的value值,也就是里面真正被开启的按钮值。
第二段ButtonToggleGroup中我们加入了mutiple
,让里面的ButtonToggle可以复选,另外加上了vertical="true"
改变排列方式,不过在复选时我们无法直接使用buttonToggleGroup.value来取得值,因此只能各自取得里面的ButtonToggle的选取状态。
效果如下:
关于ButtonToggleGroup中mutiple
的设定,值得注意的是没有加上mutiple
时,我们可以直接取用其中的value,来得到被选取的状态,同时也支援使用ngModel;加上mutiple
后,由于不会有资料传入value中,因此ngModel也因此无法使用了。
详细的其他属性可以参考ButtonToggle的API文件。
介绍一个官方文件没有提到,但官方source code的demo app有示范的一个有趣的东西,也就是涟漪效果,这个效果主要用在按钮上面,在许多其他元件也可看到这个特效的踪影,在刚刚的介绍中我们也看到了按下按钮后会产生的特效;实际上这个特效有写成一个directive,让我们可以在不同地方使用,而且能调整许多细节。
首先加入MatRippleModule后,我们先来个简单的版本,直接用一个div并加上mat-ripple
这个directive就好!
<div class="demo-ripple-container" mat-ripple>
我们在这边加上了一个class的设定
.demo-ripple-container {
height: 150px;
width: 200px;
position: relative;
transition: all 200ms linear;
border: 1px solid black;
}
position和transaition是必要的,其他可以依照情况设定,只要有这样的设定,立刻就可以为我们的画面加上涟漪效果啦!
除了基本的设定外,mat-ripple
还有其他属性可以设定,让画面呈现更加不一样,以下是mat-ripple
的主要属性
matRippleCentered
:true代表不管滑鼠在元件上的哪里点下去,都会从中心点开始产生涟漪。
matRippleDisabled
:true代表取消元件上的涟漪效果。
matRippleUnbounded
:true代表涟漪的效果扩大后会超过元件之外。
matRippleRadius
:涟漪产生的大小,数值越大大表大小越大。
matRippleCol
:涟漪的颜色。
matRippleSpeedFactor
:涟漪扩散的速度,数值越大速度越快
例如以下程式码,我们可以在画面上产生数个粉红色且扩散速度慢的涟漪点。
<div class="demo-ripple-container" mat-ripple
[matRippleCentered]="false"
[matRippleDisabled]="false"
[matRippleUnbounded]="false"
[matRippleRadius]="10"
[matRippleColor]="'pink'"
[matRippleSpeedFactor]="0.5"></div>
结果如下:
我们也能从程式里面去直接触发涟漪的产生,如下:
export class AppComponent implements OnInit {
@ViewChild(MatRipple) ripple: MatRipple;
triggerRipple() {
const point1 = this.ripple.launch(0, 0, { color: 'pink', centered: true, persistent: true, radius: 50 });
const point2 = this.ripple.launch(0, 0, { color: 'yellow', centered: true, persistent: true, radius: 20 });
setTimeout(() => {
point1.fadeOut();
}, 500);
}
clearRipple() {
this.ripple.fadeOutAll();
}
}
ripple.launch
的前两个参数为涟漪点产生的位置,但目前这个计算会跑掉,所以我们在第三个参数中设定相关属性时将centered设为true,强制从中心点开始,另外这边我们加了一个persistent为true,代表涟漪点产生后不会自动淡出。我们可以透过fadeOutAll()
把所有涟漪点都淡出。
效果如下:
是不是很有趣啊!
今天我们介绍了非常实用的元件-按钮,按钮可以说是一切互动的开始,透过按钮我们可以期待会有事情发生,而在Material Design中对于按钮的设计也是一门学问,如何在低调与奢华的按钮之间选择,影响了使用者对画面的观感。
除此之外我们也介绍了开关型的按钮,这种按钮在特定的情境下会非常实用。
最后我们额外介绍了文件目前没有的涟漪效果,这个效果在许多元件中都能看到,因此拉出来变成一个独立的directive也是件正常不过的事情,除此之外mat-ripple
还能有许多更细部的设定,让效果更加丰富。
在介绍过几个实用的元件及功能后,明天开始我们就要开来组合各种元件,并且完成各式各样的画面啦!!
本日的程式码GitHub:https://github.com/wellwind/it-ironman-demo-angular-material/tree/day-04-mat-button
分支:day-04-mat-button
官方的DEMO里面很多文件没写的宝物XD
没错没错~文件还在努力进步中,但看sample code却可以挖到很多宝XD
***已***凸显按钮的存在
立刻就可以为我们***鹅***画面加上涟漪的效果啦
感谢回馈,不知道为什么这样的错误却让我喷笑了XD
来自 https://ithelp.ithome.com.tw/articles/10193055
我们终于要正式开始时做一个后台(dashboard)画面啦,今天我们会先使用Angular Material的SideNav元件,把边栏的空间先切出来,这个空间通常是用来放置主选单的空间,我们就来看看该如何开始吧!
在Material Design的架构指南中,一个应用程式不管是行动装置、平板还是桌机,在画面基本上都可以分为3个区块,toolbar、sidenav和content
图片来源:https://material.io/guidelines/layout/structure.html#structure-ui-regions
Toolbar:通常用来放置基本的品牌logo、简单的搜寻、常用的功能和切换左右sidenav的按钮等等。
SideNav:放置使用者资讯,或是主要的功能选单等等、可以选择常驻在左边或右边,也可以选择平常隐藏起来,需要的时候可以动态的打开来。
Content:当然就是主要的功能画面啦。
在使用SideNav前,我们一样要将MatSidenavModule
加入,这个步骤之前已经做过很多次了,就只说明不介绍步骤;另外由于我们之后会再持续设计部落格页面、问卷页面等等,因此已将程式切割到不同的Module中并设定好routing,由于这是属于Angular基本知识,这里也不再多做说明,程式码都在GitHub上,可以直接参考。
加入MatSidenavModule
后,我们就可以直接开始使用,基本上SideNav分为3个区块
<mat-sidenav-container>
:代表整个包含边栏导览的容器
<mat-sidenav>
:实际上边栏导览的内容
<mat-sidenav-content>
:导览以外的实际内容
因此我们的画面程式码可以简单写成如下:
<mat-sidenav-container>
<mat-sidenav #sideNav>
我是左邊選單
</mat-sidenav>
<mat-sidenav-content>
<button mat-button (click)="sideNav.toggle()">切換左邊選單狀態</button>
<router-outlet></router-outlet>
</mat-sidenav-content>
</mat-sidenav-container>
一个包含导览功能的选单就已经出现啦!不过这时候我们的画面上还不会将选单显示出来,这是因为Angular Material预设的<mat-sidenav>
是隐藏的,不过我们可以透过程式把选单叫出来,所以画面上我们先建立了一个按钮,透过这个按钮呼叫sideNav的toggle()
方法,来切换左边导览列的显示状态。
结果如下:
我们可以透过open()
、close()
和toggle()
来控制SideNav的显示状态,这些方法都会回传一个Promise<MatDrawerToggleResult>
来告诉你SideNav的显示状态。
toggleSideNav(sideNav: MatSidenav) {
sideNav.toggle().then((result: MatDrawerToggleResult) => {
console.log(result);
console.log(`選單狀態:${result.type}`);
});
}
结果如下:
除此之外SideNav还有opened
和closed
,两个output,当SideNav被打开或关时,就会触发。
<mat-sidenav #sideNav (opened)="opened()" (closed)="closed()">
<mat-side-nav>
有一个mode属性,可以用来决定SideNav的呈现方式,目前有3个值可以设定
over:预设值,SideNav会浮动在画面之上,背后会出现一个灰底的backdrop,点击SideNav以外的地方(或按下ESC)会隐藏起来。
push:跟over类似,但显示的时候会把画面往另外一个方向推,同时也会有一个灰底的backdrop,在萤幕较大的装置时可以同时浏览SideNav和选单,但在行动装置等小萤幕上则比较没有感觉。
side:效果类似push,但不会出现灰底的backdrop,因此可以同时操作主要的content画面以及SideNav的内容。
透过opened
属性,我们可以不需要使用元件的open()
或toggle()
方法来打开,只需要设定这个属性即可变更显示状态,true代表显示,false代表隐藏。因此当我们需要一个固定在旁边的导览选单时,可以同时将mode设为side,并将opened设为true,即可让导览选单常驻在旁边,只要不在程式中切换这些状态,就不会被隐藏。
<mat-sidenav opened="true" mode="side"></mat-sidenav>
SideNav支援显示在画面的起始( start
,预设值,通常是左边)或结束( end
,通常是右边),我们可以透过设定position
决定SideNav要放在哪边,同时我们也能左右各提供一个导览选单。
<mat-sidenav opened="true" mode="side">
<div>我是左邊選單</div>
</mat-sidenav>
<mat-sidenav opened="true" mode="side" position="end">
<div>我是右邊選單</div>
</mat-sidenav>
结果如下:
不过需要注意的是,左右都只能有1个SideNav,因此以下写法都是不正确的
<mat-sidenav opened="true" mode="side">
<div>我是左邊選單</div>
</mat-sidenav>
<mat-sidenav opened="true" mode="side" position="start">
<div>我是左邊選單2號</div>
</mat-sidenav>
<mat-sidenav opened="true" mode="side" position="end">
<div>我是右邊選單</div>
</mat-sidenav>
<mat-sidenav opened="true" mode="side" position="end">
<div>我是右邊選單2號</div>
</mat-sidenav>
当这样的状况出现时,会看到以下的错误讯息
在mode设为over
或push
时,预设会出现一个backdrop,当点选backdrop或按下esc
时则会自动隐藏SideNav,如果希望不要自动隐藏,则可以设定disabledClose
,有了这个属性就必须另外在可点选的范围内加上程式设定隐藏SideNav。
<mat-sidenav #sideNav mode="over" disableClose>
<div>我是左邊選單</div>
<div>
<button mat-raised-button color="warn" (click)="toggleSideNav(sideNav)">切換選單狀態</button>
</div>
</mat-sidenav>
当我们有一个toolbar在上层时,预设SideNav现时不会挡住toolbar
<mat-toolbar>我是Toolbar</mat-toolbar>
<mat-sidenav-container>
<mat-sidenav #sideNav mode="over">
<div>我是左邊選單</div>
<div>
<button mat-raised-button color="warn" (click)="toggleSideNav(sideNav)">切換選單狀態</button>
</div>
</mat-sidenav>
...
</mat-sidenav-container>
如下图:
这时候我们可以设定fixedInViewport="true"
,让SideNav能够显示在Toolbar之上。另外也能设定fixedTopGap
和fixedBottomGap
,保留一定程度的上下空间。
<mat-sidenav #sideNav mode="over" fixedInViewport="true" fixedTopGap="20" fixedBottomGap="20"></mat-sidenav>
结果如下:
关于Toolbar的使用方式会在明天详细说明。
除了SideNav之外,Angular Material还提供了一个类似的component-<mat-drawer>
。比起SideNav是设计给整个画面使用,Drawer则是提供给放在content里面小范围区块使用。除了不支援fixedInViewport
(毕竟没有需要遮挡的toolbar了)以外,这个drawer component使用上基本和sidenav完全相同,
<mat-drawer-container style="height:100px;border: 1px solid black">
<mat-drawer mode="side" opened="true">Drawer Side</mat-drawer>
<mat-drawer-content>Content</mat-drawer-content>
</mat-drawer-container>
结果如下:
今天我们介绍了SideNav相关的元件,这是Material Design设计中对于一个基本的APP很重要的环节,因次SideNav也提供来了很多微调显示效果,让我们在设计时更能够应付不同的情境。
明天我们将介绍画面结构的另一个重要component-Toolbar
本日的程式码GitHub:https://github.com/wellwind/it-ironman-demo-angular-material/tree/day-05-sidenav
分支:day-05-sidenav
通常用来放置基本的品牌***log***
感谢回馈,log和logo傻傻分不清楚XD
很精采的文章。如果在Sidenav 加router-link, 按下时,component 是不是在sidebar-nav-content 内的router-outlet 出现?
谢谢您的肯定^^,关于您的问题,答案是肯定的,这跟Angular原始的routing机制没有不同
谢
HI~谢谢您的分享!!
请问sidenav 是否可以做成有accordion 式的material tag 呢?
我想做一个类似如下的sidenav
AAA
BBB
|_ BBB1
|_ BBB2
CCC
|_CCC1
|_CCC2
谢谢~~
您好,请问您的意思是sidenav「里面」要放置accordion的选单吗?
基本上sidenav里面可以放置任何东西,如果是tree的结构选单的话,目前Angular Material还没有提供,但可以参考使用Expansion Panel
https://ithelp.ithome.com.tw/articles/10196478
或是使用其他套件,或自行设计
谢谢
我是要在sidenav中放入accordion选单!!
目前改成使用您说的expansion panel
感谢~
我的灰底backdrop没有如预设的状况下出现呢orz,不知什么原因,所以也无法点击backdrop来隐藏,over, push都没有如期出现
状况描述看起来是没有正确的载入CSS,请参考安装篇的步骤
感谢我再一个个试试看是哪个没装上去
大神好@@
< mat-toolbar >那边似乎要加入MatToolbarModule才可以使用
这篇文章中似乎没有提到(不过下一篇有XD)
disableClose
在mode设为over或push时.......如果希望不要自动隐藏,则可以设定disabledClose
。
disabledClose 多了个 d
来自 https://ithelp.ithome.com.tw/articles/10193290
在昨天介绍SideNav时,我们有稍微提到过Toolbar,今天我们就比较认真的来看看Material Design中Toolbar的特性,及Angular Material中Toolbar可以呈现什么样的变化吧!
在Material Design的Toolbar设计指南中,Toolbar通常会浮动在整个系统的正上方,所有的内容应该从toolbar下方通过,除非是暂时性显示的元件如dialog等等。我们可以把Toolbar当作整个系统的header(或footer)角色,在这里放置品牌Logo、标题、和一些简单的执行动作等等。
Toolbar的元件放置在MatToolbarModule之中,加入这个module后,我们可以使用mat-toolbar
在画面上呈现一个简单的toolbar
<mat-toolbar>
<span>IT鐵人賽-Angular Material Demo</span>
</mat-toolbar>
效果如下:
可以看到我们已经加入一个简单的toolbar了,不过这样还有点小小问题,就是我们的toolbar没有浮动在画面的最上方,随着画面卷动,toolbar会消失在画面之中,由于toolbar只是一个component,可以在画面中的任何地方加入,因此直接强制显示在画面的最上方在元件设计上也好像怪怪的,但这只是元件设计上的问题而已,要让这个toolbar固定在最上方其实也不困难,设定一下CSS就好了!
.demo-app-header {
position: fixed;
top: 0;
z-index: 2;
}
.demo-app-container,
.demo-app-sidenav {
position: absolute;
padding-top: 64px;
height: calc(100vh - 64px);
}
目的是将toolbar固定在上方,并透过z-index: 2
来避免卷动时被下方内容盖过,mat-sidenav-container
跟mat-sidenav
乔出一个上方64px的空间给toolbar使用,避免内容被toolbar盖过。
接着将原来的元件套上这些样式
<mat-toolbar class="demo-app-header">
<span>IT鐵人賽-Angular Material Demo</span>
</mat-toolbar>
<mat-sidenav-container class="demo-app-container">
<mat-sidenav class="demo-app-sidenav">
...
</mat-sidenav>
<mat-sidenav-content>
<router-outlet></router-outlet>
</mat-sidenav-content>
</mat-sidenav-container>
需要特别注意的是,前一天我们在
mat-sidenav
设定了fixedInViewport
,在CSS调整后这个属性会造成sidenav显示跑掉,因此我们要这个设定拿掉,目前GitHub上已有Issue在讨论了,希望之后会调整啰。
成果如下:
跟其他Angular Material元件一样,我们可以透过color
来改变toolbar的颜色:
<mat-toolbar color="primary">這是primary的toolbar</mat-toolbar>
<mat-toolbar color="accent">這是accent的toolbar</mat-toolbar>
<mat-toolbar color="warn">這是warn的toolbar</mat-toolbar>
成果如下:
接着我们想在toolbar加上一些东西,第一个是在左边加上一个icon,可以透过这个icon来开关SideNav,这是一种很常见的后台做法
<mat-toolbar color="primary" class="demo-app-header">
<button mat-icon-button (click)="sideNav.toggle()">
<mat-icon>{{ sideNav.opened ? 'close' : 'menu' }}</mat-icon>
</button>
<span>IT鐵人賽-Angular Material Demo</span>
</mat-toolbar>
效果如下:
接着我们想在toolbar的最右边加上一个登出的按钮,不过要怎么把按钮推到最右边去呢,其实只要透过CSS就可以轻易解决,由于Toolbar内的排版是flex,我们可以加入一个分隔用的空间,把空间后的内容都推到另外一边去。
.toolbar-seprator {
flex: 1 1 auto;
}
接着在toolbar中加入这个分隔器
<mat-toolbar color="primary" class="demo-app-header">
<button mat-icon-button (click)="sideNav.toggle()">
<mat-icon>{{ sideNav.opened ? 'close' : 'menu' }}</mat-icon>
</button>
<span>IT鐵人賽-Angular Material Demo</span>
<!-- 在這之後的都會被推到右邊去 -->
<span class="toolbar-seprator"></span>
<button mat-icon-button>
<mat-icon>message</mat-icon>
</button>
<button mat-icon-button>
<mat-icon>exit_to_app</mat-icon>
</button>
</mat-toolbar>
效果如下:
一个有模有样的toolbar就出现啦!
Toolbar预设是单行的,在mat-toolbar
中的内容预设都会在同一行显示,若在一行toolbar中放入太多资讯则可能会因为宽度有限的关系无法显示,这时候我们可以用多个<mat-toolbar-row>
来设定多行的toolbar。
<mat-toolbar color="primary">
<mat-toolbar-row>
<span>第一行Toolbar</span>
<span class="toolbar-seprator"></span>
<mat-icon>favorite</mat-icon>
</mat-toolbar-row>
<mat-toolbar-row>
第二行Toolbar
<span class="toolbar-seprator"></span>
<mat-icon>delete</mat-icon>
</mat-toolbar-row>
</mat-toolbar>
效果如下:
乍看之下跟用多个<mat-toolbar>
很类似,但<mat-toolbar-row>
本身是没有color
可以设定的,而是跟随着mat-toolbar
走,另外在语义上也有所不同,在CSS状况比较复杂时,也可能造成画面错乱的问题,因此应该看情境决定使用的时机。
今天我们学会了另一个前端上常用的元件-Toolbar,Toolbar算是相对简单的元件,也因为他的简单,给了开发人员更多的弹性空间去灵活调整,不管是在整个页面架构上,还是系统内的功能画面,都有很大的机会去使用到,好好熟练Toolbar的用法对于功能画面的开发会很有帮助喔!
明后天我们再来学习使用其他元件,来丰富这两天学到的SideNav和Toolbar的内容吧!
本日的程式码GitHub:https://github.com/wellwind/it-ironman-demo-angular-material/tree/day-06-toolbar
分支:day-06-toolbar
请问flex: 1 1 auto 这三个值分别是?
hello, 以下文章给您参考:
http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html
简单来说是在中间加一个分隔用的span, 这三个数值分别代表的是放大比例/缩小比例/剩余空间的分配
第3个值设定为auto,代表在空间分配时会占满剩下可用的空间,因此会把之后的内容都推到另外一边去
WOW~~看懂了,好特别的技巧!
感谢。
请问Angular material 有没有像bootstrap 的button group ?把buttons 放在group, 再心摆在toolbar 上,可以省下空间。
ButtonToggleGroup可以达到类似的效果,但可能需要自行挑整一下
https://ithelp.ithome.com.tw/m/articles/10193055
所以Toolbar相对于header也可用于footer的设计,Material就没再另外做出footer的相关设计了,想请问一下footer如何实作比较适当,也是要独立于sidenav之外(然后再空出一个空间给他?),还是在mat-sidenav-content之内的底部?
footer直接用toolbar就可以了没错, 至于具体的要放在哪里, 就看需求而定了, 没有一定的规则
有的内容应该从toolbar下放通过←这里应该是下"方"?
已修正啰
来自 https://ithelp.ithome.com.tw/articles/10193505
昨天我们把整个后台系统的架构基本上完成了,今天我们要来学习使用Angular Material的List元件,来填满SideNav。List元件功能非常强大,而且也是个在任何地方都很有可能会用到的功能,善用List可以产生各种不同的变化来满足各种需求,Let's GO!
在Material Design的List设计指南中,List是在一栏中呈现多个资料列,每一列就是一组资料,在资料列中我们能够清楚的呈现相关的资讯,如果有需要,也能够对这些资讯进行一些额外的操作。
一个资料列基本上会包含3种资料,非必要但可以参考:
Avatar:可以是一个头像或是Icon,用来做为这笔资料的基本代表;在画面上我们应该能从这里立即得了解资讯的大致含义。
内容:主要的文字内容,通常是单行文字,必要的时候多行文字也没有问题,只要画面能清楚呈现即可。
行动or资讯:代表资料的补充讯息,可能是个警告的icon,或是一个按下去会有其他行为的按钮等等。
图片来源:https://material.io/guidelines/components/lists.html#lists-specs
使用List元件前,我们必须加入MatListModule
,之后可以使用<mat-list>
及<mat-list-item>
的组合来完成一个基本的List:
<mat-list>
<mat-list-item>問卷調查</mat-list-item>
<mat-list-item>部落格</mat-list-item>
<mat-list-item>收件夾</mat-list-item>
</mat-list>
结果如下:
这是一个很单纯的清单资料,不过我们在SideNav中,希望是能够点选的Link,好在<mat-list-item>
不仅仅是component,也能够以directive的方式呈现,因此我们稍微做点调整:
<mat-list>
<a [routerLink]="['/', 'dashboard', 'survey']" mat-list-item>問卷調查</a>
<a [routerLink]="['/', 'dashboard', 'blog']" mat-list-item>部落格</a>
<a [routerLink]="['/', 'dashboard', 'inbox']" mat-list-item>收件夾</a>
</mat-list>
结果如下:
一个可以点选的List就出现啦!这里可以注意到一件非常有趣的事情,当我们展开选单时,预设会focus在第一个项目,同时我们可以使用tab
来切换,更棒的是使用tab
切换时,不会切换到List之外的内容,只会在List之内循环,许多清单类型的Angular Material都具有这样的特性,让使用键盘操作时的情境可以更加灵活。
我们也能够在自己的component中做到这个特性,这在未来的Angular CDK篇时会再作介绍。
刚刚的例子我们已经在SideNav导览列中加入了选单,但是在导览列的选单连结中有底线有违我们一般的习惯,我们可以用CSS把它调整调,但Angular Material提供了更优质的做法,也就是另一个元件mat-nav-list
,这个元件可以使用在导览用的list中,我们只要把原来的mat-list
换掉即可
<mat-nav-list>
<a [routerLink]="['/', 'dashboard', 'survey']" mat-list-item>問卷調查</a>
<a [routerLink]="['/', 'dashboard', 'blog']" mat-list-item>部落格</a>
<a [routerLink]="['/', 'dashboard', 'inbox']" mat-list-item>收件夾</a>
</mat-nav-list>
结果如下:
可以看到不仅底线不见了,连focus的样式也变成灰底而不是系统预设的蓝色外框,我们一样能用tab在这些清单项目中切换,同时点下去还有涟漪的特效,操作爽度百分百!
当清单料很多时,我们可能会需要将资料分类显示,这时候我们可以使用matSubheader
,替每组资料标上一个分类名称。
除此之外,我们也可以使用<mat-divider>
这个来分隔不同群组的资料。
<mat-nav-list>
<h3 matSubheader>示範用頁面</h3>
<a [routerLink]="['/', 'dashboard', 'survey']" mat-list-item>問卷調查</a>
<a [routerLink]="['/', 'dashboard', 'blog']" mat-list-item>部落格</a>
<a [routerLink]="['/', 'dashboard', 'inbox']" mat-list-item>收件夾</a>
<mat-divider></mat-divider>
<!-- 另外一組選單 -->
<h3 matSubheader>其他頁面</h3>
<a [routerLink]="['/']" mat-list-item>首頁</a>
<a [routerLink]="['/']" mat-list-item>Google</a>
<a [routerLink]="['/']" mat-list-item>Facebook</a>
</mat-nav-list>
结果如下:
可以看到matSubheader
的内容会变成灰色的文字说明,而且也不会被tab选中。同时被<mat-divider>
分隔的两组选单之间也多了一条灰色的线,让分隔更加明确。
<mat-list-item>
预设是一行文字,但当有需要的时候,我们也可以使用matLine
来建立多行文字。
<mat-nav-list>
<h3 matSubheader>多行文字示範</h3>
<mat-list-item>
<p matLine>床前明月光</p>
<p matLine>疑是地上霜</p>
</mat-list-item>
<mat-list-item>
<p matLine>參加IT鐵人賽</p>
<p matLine>功力增加一甲子</p>
</mat-list-item>
</mat-nav-list>
结果如下:
可以发现我们没有做任何设定,但第一行的文字就是会比较大点,因为第一行文字通常代表的是主要讯息,之后的文字则是以补充为主,因此会小一点点。
在清单中使用头像是很常见的一种应用,像是许多通讯软体都会采用这种设计方式,要在清单中使用头像可以在头像加上matListAvatar
:
<h3 matSubheader>好友訊息</h3>
<mat-list-item>
<img matListAvatar src="..." />
<p matLine>志玲</p>
<p matLine>hi,好久不見,最近好嗎?</p>
</mat-list-item>
<mat-list-item>
<img matListAvatar src="..." />
<p matLine>依晨</p>
<p matLine>找時間吃個飯吧?</p>
</mat-list-item>
结果如下:
在Material Design中的清单,所有的执行动作按钮预设都会放在最后方,因此在Angular Material中,只要加入按钮,都会直接被推到最后面:
<mat-list-item>
<img matListAvatar src="..." />
<p matLine>志玲</p>
<p matLine>hi,好久不見,最近好嗎?</p>
<!-- button會自動被推到最後面 -->
<button mat-icon-button><mat-icon>chat</mat-icon></button>
</mat-list-item>
<mat-list-item>
<!-- 即使icon button放在前面,還是會被往後推 -->
<button mat-icon-button><mat-icon>chat</mat-icon></button>
<img matListAvatar src="..." />
<p matLine>依晨</p>
<p matLine>找時間吃個飯吧?</p>
</mat-list-item>
结果如下:
在List中,还有一个比较复杂的component-<mat-selection-list>
及<mat-list-option>
,可以让清单变成可复选的列表,并自动在清单列后方加上一个checkbox,在一些功能设定的页面非常好用。
<mat-nav-list>
<h3 matSubheader>
<mat-icon>chat_bubble</mat-icon>
新訊息
</h3>
<mat-list-item *ngIf="optNew.selected">這是新消息</mat-list-item>
<mat-list-item *ngIf="optAds.selected">這是廣告消息</mat-list-item>
<mat-divider></mat-divider>
<h3 matSubheader>
<mat-icon>settings</mat-icon>
訊息設定
</h3>
<mat-selection-list>
<mat-list-option [value]="1" selected="true" #optNew>有新訊息時通知我</mat-list-option>
<mat-list-option [value]="2" #optAds>顯示廣告訊息</mat-list-option>
</mat-selection-list>
</mat-nav-list>
成果如下:
更多<mat-selection-list>
和<mat-list-option>
的API可以参考官方文件。
今天我们把Angular Material的List功能整个玩过了一遍,并且为原来的SideNav填入了各式各样的List,List可是说是泛用性非常高的一个元件,因此把List学好,对于前端画面的设计绝对是有很大的加分效果。
明天我们在学习另一个元件-Menu,来把上方的Toolbar也变得更加丰富吧!
本日的程式码GitHub:https://github.com/wellwind/it-ironman-demo-angular-material/tree/day-07-list
分支:day-07-list
很生动的sidebar
这样感觉会比较有趣XD
来自 https://ithelp.ithome.com.tw/articles/10193798
今天我们要来讲Angular Material的Menu元件,Menu可以说是非常具有历史性的功能,使用机会也不低,只要有一系列的选择要浓缩在一个范围内时,就是使用Menu的好时机,接下来就让我们看看Angular Material强大的Menu元件吧!
在Material Design的Menu设计指南中,Menu可以用来显示一系列的选项,每一列就是一个选项,通常由一个按钮,或一个简单的文字label开始,在画面上进行立体的呈现,而不会影响到其他元素的排版。
在桌面应用上Menu可以是多层串接的,在行动装置或平板上则建议一层简单的Menu就好,另外Menu的选项也应该是可以被disable的。
图片来源:https://material.io/guidelines/components/menus.html#
要使用Menu元件,首先要先加入MatMenuModule
。
我们使用<mat-menu>
来为原来toolbar的message icon加上Menu选单,首先我们可以在任意地方加入<mat-menu>
与<mat-menu-item>
组合的选单。
<mat-menu #messageMenu="matMenu">
<button mat-menu-item>最新訊息</button>
<button mat-menu-item>訊息設定</button>
</mat-menu>
这时候画面上还不会有任何资料,还需需要一个可以触发显示选单的来源,我们加在toolbar上的message icon上
<button mat-icon-button [matMenuTriggerFor]="messageMenu" #menuTrigger="matMenuTrigger">
<mat-icon>message</mat-icon>
</button>
上面程式我们透过matMenuTriggerFor
来设定这个按钮会触发哪一个menu元件,这时候我们可以执行看看结果:
点击看看原来的message icon按钮,可以发现menu选单就跳出来啦!这时候我们可以使用上下键来切换focus的选项,也可以按下Enter键来触发按钮的click事件,操作上超级方便的!
要在程式中开启选单很容易,只要找到matMenuTriggerFor
,再触发他的openMenu()
方法就可以打开menu,透过closeMenu()
则能够动态的关闭menu,另外我们也可以透过toggleMenu()
来开关menu的显示状态
<button mat-raised-button (click)="menuTrigger.toggleMenu()">開啟訊息設定</button>
效果如下:
<mat-menu>
预设会在出现时把整个menuTrigger覆盖掉,同时也会根据目前所在的位置来决定选单生长的方向,例如按钮在画面的右边的话,选单预设会往左边长,在画面上方的话,选单预设会往下长,总之就是会尽量让整个menu在画面中可以被看到就对了,我们可以能够透过xPosition
和yPosition
,来控制生长的方向
xPosition:选项为after
(预设值、从start往end的方向长,通常是从左到右)或before
(从end往start的方向长,通常是从右到左)。
yPosition:选项为below
(预设值、从上往下长)或above
(从下往上长)
举例来说,一个没有设定xPosition
和yPosition
,且生长方向没有阻碍时的程式码和画面如下:
<div style="text-align:center">
<button mat-raised-button [matMenuTriggerFor]="positionMenu">開啟訊息設定,這是一條比較長的按鈕,好確認Menu的生長方向</button>
<mat-menu #positionMenu="matMenu">
<button mat-menu-item>訊息1</button>
<button mat-menu-item>訊息2</button>
</mat-menu>
</div>
当我们调整xPosition
和yPosition
如下时:
<mat-menu #positionMenu="matMenu" xPosition="before" yPosition="above">
<button mat-menu-item>訊息1</button>
<button mat-menu-item>訊息2</button>
</mat-menu>
可以看到生长的方向就变了,有趣的是当我们往下卷动萤幕时,由于menu即将碰到顶端,会立刻改为往下生长,尽可能让选单可以被看到,只能说Angular Material既贴心又聪明啊!
同样的当生长方向收到阻碍时,Angular Material会自动帮我们计算要成长的方向
<!-- 按鈕在畫面的很上方,即使設定往上長,當上方空間不足時,會自動往下生長 -->
<mat-menu #positionMenu="matMenu" xPosition="before" yPosition="above">
<button mat-menu-item>訊息1</button>
<button mat-menu-item>訊息2</button>
...
<button mat-menu-item>訊息5</button>
</mat-menu>
另外,我们也可以设定[overlapTrigger]="false"
,如此一来,选单就永远不会遮住我们的trigger:
<mat-menu #messageMenu="matMenu" [overlapTrigger]="false">
<button mat-menu-item>最新訊息</button>
<button mat-menu-item>訊息設定</button>
</mat-menu>
<button mat-icon-button [matMenuTriggerFor]="messageMenu" #menuTrigger="matMenuTrigger">
<mat-icon>message</mat-icon>
</button>
menu选单可以是巢状的,要使用巢状的选单没有什么新技巧,一样把子选单使用<mat-menu>
设计好,然后在原来的选单选项中加入matMenuTriggerFor
即可:
<button mat-raised-button [matMenuTriggerFor]="positionMenu">巢狀選單demo</button>
<mat-menu #positionMenu="matMenu">
<button mat-menu-item [matMenuTriggerFor]="subMenu1">訊息1</button>
<button mat-menu-item [matMenuTriggerFor]="subMenu2">訊息2</button>
<button mat-menu-item>訊息3</button>
</mat-menu>
<mat-menu #subMenu1="matMenu">
<button mat-menu-item>
<mat-icon>person</mat-icon>
訊息 1-1
</button>
<button mat-menu-item>
<mat-icon>favorite</mat-icon>
訊息 1-2
</button>
<button mat-menu-item>
<mat-icon>thumb_up</mat-icon>
訊息 1-3
</button>
</mat-menu>
<mat-menu #subMenu2="matMenu">
<button mat-menu-item>
<mat-icon>delete</mat-icon>
訊息 2-1
</button>
<button mat-menu-item disabled>
<mat-icon>settings</mat-icon>
訊息 2-2
</button>
</mat-menu>
我们在这边顺便搭配了<mat-icon>
以及尝试为button加入disabled
属性,可以看到搭配上完全都没有问题,排版依然很顺畅,同时我们也能使用左右键切换子选单:
当要呈现的选单多的时候,除了选择用巢状的选单以外,用一个divider分隔也是个不错的选择,可以减少子项目难以分类的烦恼,在行动装置的呈现上也会比较清楚。
还记得我们在昨天介绍List时有提到一个<mat-divider>
吗?虽然官方的Menu文件没有提到,但<mat-divider>
其实一样可以在<mat-menu>
中使用:
<mat-menu #positionMenu="matMenu">
<button mat-menu-item [matMenuTriggerFor]="subMenu1">訊息1</button>
<button mat-menu-item [matMenuTriggerFor]="subMenu2">訊息2</button>
<mat-divider></mat-divider>
<button mat-menu-item>訊息3</button>
</mat-menu>
成果如下,一条分隔线就出现啦:
当然,你还是必须要载入
MatListModule
才可以。
关于Menu的使用基本上不会很困难,但实用性却很高,要调整显示风格也不会是太困难的事情。
Angular Material在Menu的设计上非常用心,尽管是web application,但在操作上我们依然可以轻松地使用方向键来切换不同的选项,同时也可以使用Enter来确认执行选项,可以说是非常贴心方便的设计!
介绍到这边,整个基本的后台画面就已经大致上成形了!明天开始我们将花几天的时间透过一个问卷调查的页面,来介绍Angular Material中各种不同的表单元件的使用,这些表单元件都有很丰富的动态效果,但使用上非常显示明确,不会被这些效果给混淆,敬请期待吧!!
本日的程式码GitHub:https://github.com/wellwind/it-ironman-demo-angular-material/tree/day-08-menu
分支:day-08-menu
不知不觉,这系列文章已经超过50个人订阅了,真的是对我很大的一个鼓励,也不白费我每篇文章都花3个小时左右绞尽脑汁的写出来,在这边感谢各位订阅者,也感谢有在下面留言发问、提供意见的朋友,让我更有信心把这系列写下去!最后虚荣的祈祷一下完赛前订阅数可以破百吧XD
mat-menu-Item disable 后,怎样enable? disabled 是directive吗?如何用boolean 控制状态?谢
disabled只是一个属性而已,跟一般<button disabled>
是一样的,因此可以如下:
disable:
<button mat-menu-item [disabled]="true">
enable:
<bitton mat-menu-item [disabled]="false">
got it
请问有办法直接在ToolBar上直接显示Menu的内容吗? 大概是点击Button在Button左侧显示出Menu的内容
Menu 的设计预设是会挡住内容的,如果要部挡住内容,目前只能自己套CDK 了
我们使用<mat-menu? ← 符号应该是> ?
举例来说,一个没有设定xPosition和y Position ←y 的格式跑掉了:D
多谢,已修正啰
来自 https://ithelp.ithome.com.tw/articles/10194067
昨天我们已经完成了一个基本的后台版型,今天开始我们要使用Angular Material来制作一个问卷调查的页面,这个练习主要会学到所有Angular Material的表单元件,毕竟在前端的世界里各式各样的表单是必须面临到的一大议题!不过在介绍表单元件之前,我们先来介绍一个还蛮适合放在问卷页面的元件-Stepper。
在Material Design的Stepper设计指南中,Stepper可以说是操作群组化的结果,我们可以将这些操作分成不同的群组,并且依照顺序变成几个进度,使用者可以依循这些进度完成所有步骤。
在许多元件的设计上,这也称作精灵(Wizard),不管怎么称呼,这类元件的目标很简单,就是引导使用者完成所有步骤,并得到完成步骤后的结果。因此像是注册页面、问卷调查等等,都很适合使用这样的元件来设计,避免因为太多过程而混淆。
Stepper也有许多不同的呈现模式,我们可以依照需要的不同来决定选择使用什么样的模式,例如是否允许回去编辑上一步骤,或是否一定要依循画面上的步骤去操作等等,都是设计上需要仔细考量的点。
要使用Stepper元件,首先要先加入MatStepperModule
。
Stepper基本上是一个水平或垂直的component与一系列的step的组合,先来一个水平的Stepper看看:
<mat-horizontal-stepper>
<mat-step label="個人資訊">
<h4>提供個人資訊</h4>
</mat-step>
<mat-step label="詳細問題">
<h4>主要的問題內容</h4>
</mat-step>
<mat-step label="其他">
<h4>其他問題</h4>
</mat-step>
</mat-horizontal-stepper>
在上述程式中,我们使用<mat-horizontal-stepper>
作为一个水平stepper的容器,接着每个步骤都以一个<mat-step>
包装起来,对于每个步骤的基本标题文字则使用<mat-step>
的label
属性。
成果如下:
各式各样的特效真是百看不厌啊!
这个元件一样是可以透过方向键、Tab和Enter键来互动的,有兴趣的读者可以玩玩看!
如果希望改为垂直排列,只需要将最外面的<mat-horizontal-stepper>
改为<mat-vertical-stepper>
即可,效果如下:
如果显示的label想要以比较复杂的方式呈现,可以再<mat-step>
里面加上一个带有matStepLabel
directive的<ng-template>
元素,如下:
<mat-vertical-stepper>
<mat-step>
<ng-template matStepLabel>
<u>個人資訊</u>
</ng-template>
<h4>提供個人資訊</h4>
</mat-step>
<mat-step>
<ng-template matStepLabel>
<em>詳細問題</em>
</ng-template>
<h4>主要的問題內容</h4>
</mat-step>
<mat-step label="其他">
<h4>其他問題</h4>
</mat-step>
</mat-vertical-stepper>
结果如下:
我们可以在<mat-step>
中使用按钮并透过matStepperNext
和matStepperPrevious
来动态切换不同的步骤,如下:
<mat-vertical-stepper>
<mat-step>
<ng-template matStepLabel>
<u>個人資訊</u>
</ng-template>
<h4>提供個人資訊</h4>
<button mat-button matStepperNext>前進到「詳細問題」</button>
</mat-step>
<mat-step>
<ng-template matStepLabel>
<em>詳細問題</em>
</ng-template>
<h4>主要的問題內容</h4>
<button mat-button matStepperPrevious>回到「個人資訊」</button>
<button mat-button matStepperNext>前進到「其他」</button>
</mat-step>
<mat-step label="其他">
<h4>其他問題</h4>
<button mat-button matStepperPrevious>回到「詳細問題」</button>
</mat-step>
</mat-vertical-stepper>
结果如下:
Stepper有一个linear
属性可以设定,这个属性设定后,如果step内的表单是invalid
的话,就会无法前进到下一步,这个设定比较复杂,且必须搭配表单验证(form validation)来处理,让我们先看code ,再来解释内容:
我们使用ReactiveForm,首先在component.ts中加入一个可以用来切换linear状态的变数,以及一个FormGroup
:
export class SurveyComponent {
isLinear: boolean;
basicFormGroup: FormGroup;
constructor() {
this.basicFormGroup = new FormGroup({
name: new FormControl('', Validators.required)
});
}
}
接着在页面上加入切换状态的功能,以及把FormGroup
套用在第一个step的表单内:
<button mat-button (click)="isLinear = !isLinear">切換Linear狀態</button>
<mat-vertical-stepper [linear]="isLinear">
<mat-step [stepControl]="basicFormGroup">
<form [formGroup]="basicFormGroup">
<ng-template matStepLabel>
<u>個人資訊</u>
</ng-template>
<h4>提供個人資訊</h4>
<mat-form-field>
<input name="name" matInput placeholder="姓名" formControlName="name" required>
</mat-form-field>
</form>
<button mat-button matStepperNext>前進到「詳細問題」</button>
</mat-step>
<mat-step>
...
</mat-step>
<mat-step label="其他">
...
</mat-step>
</mat-vertical-stepper>
在这里我们偷偷使用了<mat-form-field>
和matInput
,这是明天会介绍到的元件,为了要展示表单与Linear Stepper的关系先偷偷拿来使用,要记得加入MatFormFieldModule
和MatInputModule
才能开始使用。
另外别忘记我们使用了ReactiveForm,因此也要记得加入ReactiveFormsModule
。
而在上面的程式码中,我们先在<mat-step>
中设定stepControl
这个设定是用来让整个step知道要以哪个form group的valid状态来决定是否可以进到下一步,接着里面就只是一般ReactiveForm的设计了。
成果如下:
刚刚我们用一个<mat-step>
对一个表单的方式,如果不喜欢这样的设计,我们依然可以使用一个大的表单包住所有Step的方式来设计,只需要同时设计一个大的巢状FormGroup
即可,让我们先来看看component.ts的内容:
export class SurveyComponent implements OnInit {
isLinear: boolean;
surveyForm: FormGroup;
constructor() {
this.surveyForm = new FormGroup({
basicQuestions: new FormGroup({
name: new FormControl('', Validators.required)
})
});
}
}
接着画面修改为:
<form [formGroup]="surveyForm">
<mat-vertical-stepper [linear]="isLinear">
<mat-step formGroupName="basicQuestions" [stepControl]="surveyForm.get('basicQuestions')">
<ng-template matStepLabel>
<u>個人資訊</u>
</ng-template>
<h4>提供個人資訊</h4>
<mat-form-field>
<input name="name" matInput placeholder="姓名" formControlName="name" required>
</mat-form-field>
<div>
<button mat-button matStepperNext>前進到「詳細問題」</button>
</div>
</mat-step>
<mat-step>
...
</mat-step>
<mat-step label="其他">
...
</mat-step>
</mat-vertical-stepper>
</form>
这边我们直接在最外面用一个form包起来并指定主要的FormGroup,接着在<mat-step>
中指定内部的formGroupName
,及stepControl
,如此一来就可以用一个大的model涵盖所有step的内容啦!
如果某个step不是必要的,我们可以在<mat-step>
中设定optinoal
属性,设定了这个属性后,会在这个step的label下出现一个灰色的optional提示,不过如果有设定linear
属性的话,只要里面的form group是invalid的,依然会无法直接跳到下一步(毕竟optional只是参考用的)。
程式码如下:
<mat-step formGroupName="basicQuestions" [stepControl]="surveyForm.get('basicQuestions')" optional>
结果:
预设下,每个step都是可以被编辑的状态,不过若是希望这个状态不可以利用「上一步」切回来编辑,可以设定editable="false"
。例如:
<mat-vertical-stepper [linear]="isLinear">
<mat-step formGroupName="basicQuestions" [stepControl]="surveyForm.get('basicQuestions')" optional>
<ng-template matStepLabel>
<u>個人資訊</u>
</ng-template>
<h4>提供個人資訊</h4>
<mat-form-field>
<input name="name" matInput placeholder="姓名" formControlName="name" required>
</mat-form-field>
<div>
<button mat-button matStepperNext>前進到「詳細問題」</button>
</div>
</mat-step>
<!-- 這個step無法被切回來 -->
<mat-step editable="false">
<ng-template matStepLabel>
<em>詳細問題</em>
</ng-template>
<h4>主要的問題內容</h4>
<button mat-button matStepperPrevious>回到「個人資訊」</button>
<button mat-button matStepperNext>前進到「其他」</button>
</mat-step>
<mat-step label="其他">
<h4>其他問題</h4>
<button mat-button matStepperPrevious>回到「詳細問題」</button>
</mat-step>
</mat-vertical-stepper>
结果如下:
可以看到切到第3步骤时,按上一步的按钮就无法再切回去了!
当<mat-step>
加上optional
属性后,会显示一个灰色的英文optional
文字标签,不过Angular Material的高品质承诺包含了所有的元件如果有文字内容,都应该要可以被更改的成符合的语系内容,因此这个optional
文字内容当然也可以调整,Angular Material使用MatStepperIntl
来设定optional文字内容,其中的optionalLabel
就是用来设定显示文字的,所以我们可自订一个一样的class,然后在Angular Material的DI系统中取代原来的MatStepperIntl
:
export class TwStepperIntl extends MatStepperIntl {
optionalLabel = '非必填';
}
@Component({
selector: 'app-survey',
templateUrl: './survey.component.html',
styleUrls: ['./survey.component.css'],
providers: [{ provide: MatStepperIntl, useClass: TwStepperIntl }]
})
export class SurveyComponent implements OnInit { ... }
这里我们只针对SurveyComponent的Stepper去设定,如果希望能在所有元件使用到Stepper都用到的话,可以加在更外层的Module中。
结果如下:
如我们预期,文字内容就整个被改变啦!
今天我们介绍了Angular Material中的Stepper,完成一个简单的精灵效果,这个元件在很多复杂的表单中都有机会使用到,Angular Material针对Stepper提供了很多可以调整的细节,让步骤的变化能够更细腻!
有了基本的精灵功能之后,明天开始我们就会一步一步把所有基本Angular Material的表单元件都填入这些步骤里面,好完成一个简单的问卷系统啦!
本日的程式码GitHub:https://github.com/wellwind/it-ironman-demo-angular-material/tree/day-09-stepper
分支:day-09-stepper
来自 https://ithelp.ithome.com.tw/articles/10194261
接下我们要来介绍几个在Material Design中属于Input,也就是文字输入栏位相关的功能,文字输入也可以说是表单里面最常使用到的栏位!接下来就来看看Angular Material的Input、Autocomplete!!
在Material Design的文字栏位设计指南中,文字栏位就是提供使用者输入文字的一个空间,通常在表单中最常被使用,当然像是其他一些如搜寻功能等也很会出现,文字栏位必须要能提供验证使用者输入的资讯的功能,来帮助使用者修正问题,另外也能提供一些自动完成的功能,以提供使用者相关的建议。
文字栏位可以是单行或是多行,如果需要的话也要提供能随着行数增加和自动增加的功能。
另外,文字栏位也要能限制输入的格式,或是提供选项来选择。
要使用Input相关的功能,首先得先加入MatInputModule
。另外,部分的表单控制项,都需要搭配另一个元件-FormField来使用,因此我们也要加入MatFormFieldModule
。关于FormField元件,目前只需要简单使用就好,细节的操作会在后续的文章做详细的说明。
matInput
是一个依附于input和text的表单基本元件上的directive,因此我们只需要在input或textarea中加入matInput
这个directive,即可替元件加上基本的Material Design样式,不过为了让input和textarea能更加具有意义,我们会在外面用<mat-form-field>
包起来,这个<mat-form-field>
可以替input和textarea等元件加上更有意义的讯息,让操作上更加容易。
<div>
<mat-form-field>
<input type="text" name="nickname" matInput placeholder="暱稱" />
</mat-form-field>
</div>
<div>
<mat-form-field>
<textarea name="intro_self" matInput placeholder="自我介紹"></textarea>
</mat-form-field>
</div>
效果如下:
可以看到我们的placeholder
在这边扮演了label
的效果,而且预设会直接在输入框里面(就跟一般的placeholder一样),但是当focus到里面时,placeholder的内容就往上浮动成了一个label。
由于matInput
只是个directive,使用上是直接加到相关的input或textarea元素中,因此我们依然可以使用所有已知的input或textarea的属性,来设定我们的输入栏位。
也因此,浏览器原生的input type基本上也都支援,例如:
date
datetime-local
month
number
password
search
tel
text
time
url
week
举例来说,我们可以使用<input type="date" …/>
,来产生一个输入日期的文字栏位:
<mat-form-field>
<input type="date" name="birthday" matInput placeholder="生日" />
</mat-form-field>
结果如下:
如此即可为input家让日期选择的功能,如图这是Macbook的Google Chrome上显示的结果,但实际结果可能会因为作业系统和浏览器的不同而不同,有些浏览器可能甚至不支援这样的功能,这在现代的网页设计上是一个稍微扣分的部分,也就是在不同浏览器呈现效果可能会有极大差异的问题;不过若是设计出来的网页能确定在某个系统和浏览器上显示,这也不失为一种简单有效的做法!
关于范例中的日期选择功能,在Angular Material中有一个强大且持续在进步的Datepicker元件,明天会仔细介绍。
有时候单是使用placeholder属性可能会无法说明栏位的意义,这时候我们可以使用<mat-hint>
替栏位加上比较仔细地说明,例如:
<mat-form-field>
<textarea name="intro_self" matInput placeholder="自我介紹"></textarea>
<mat-hint>簡單介紹一下你的興趣吧!</mat-hint>
</mat-form-field>
成果如下:
当文字栏位资料有问题时,需要提示错误讯息是很常见的事情,关于这点我们可以用<mat-error>
来显示错误的讯息,程式如下:
<mat-form-field>
<textarea name="intro_self" matInput placeholder="自我介紹" required></textarea>
<mat-hint>簡單介紹一下你的興趣吧!</mat-hint>
<mat-error>請記得輸入自我介紹喔!</mat-error>
</mat-form-field>
结果如下:
只要同一个<mat-form-field>
区间里面的输入栏位有错误,这个错误讯息就会跳出来。
假如我们希望针对不同的错误跳出不同的讯息,只需要使用ngIf
或ngSwitch
来依照错误类型来决定显示与否即可:
<mat-form-field>
<textarea name="intro_self" matInput placeholder="自我介紹" formControlName="intro" required></textarea>
<mat-hint>簡單介紹一下你的興趣吧!</mat-hint>
<mat-error *ngIf="surveyForm.get('basicQuestions').get('intro').hasError('required')">請記得輸入自我介紹喔!</mat-error>
<mat-error *ngIf="surveyForm.get('basicQuestions').get('intro').hasError('minlength')">至少輸入10個字吧!</mat-error>
</mat-form-field>
结果如下:
预设情境下,错误显示的时机必须符合dirty、touched和invalid的状态,才会显示错误讯息,因此以刚刚的状况来说,我们在一开始输入文字时,由于符合dirty和invalid的状态,但是因为第一次进入不会是touched状态,因此一开始不会立刻显示错误讯息,而是在离开栏位后,状态也变更为touched后,才会显示错误。
如果希望自己决定错误显示的时机,可以实作ErrorStateMatcher
这个介面的isErrorState
方法,来决定何时该显示,为传true代表要显示错误;并在input的errorStateMatcher
(加上matInput
后扩充的功能)指定我们自订的macher即可,实际来写点程式看看吧,我们先在component.ts实作这个macher
// 調整時機為invalid + dirty即顯示錯誤訊息
export class EarlyErrorStateMatcher implements ErrorStateMatcher {
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const isSubmitted = form && form.submitted;
return !!(control && control.invalid && control.dirty);
}
}
export class SurveyComponent {
surveyForm: FormGroup;
earlyErrorStateMacher = new EarlyErrorStateMatcher();
}
接着在input中加入这个macher
<mat-form-field>
<textarea name="intro_self" matInput placeholder="自我介紹" formControlName="intro" required [errorStateMatcher]="earlyErrorStateMacher"></textarea>
<mat-hint>簡單介紹一下你的興趣吧!</mat-hint>
<mat-error *ngIf="surveyForm.get('basicQuestions').get('intro').hasError('required')">請記得輸入自我介紹喔!</mat-error>
<mat-error *ngIf="surveyForm.get('basicQuestions').get('intro').hasError('minlength')">至少輸入10個字吧!</mat-error>
</mat-form-field>
结果如下:
当我们一进入文字栏位并输入内容时,立即符合了我们自订的macher规则,所以不用等到移出焦点后变成touched状态,就会提早显示错误啦!
如果要在全域的范围套用这个规则,可以在providers中注入这个macher
providers: [
{provide: ErrorStateMatcher, useClass: EarlyErrorStateMatcher}
]
就能够为注入范围内的输入栏位套上规则啰。
我们可以为textarea加上自动调整大小功能,只需要加入matTextareaAutosize
这个directive即可:
<textarea name="intro_self" matInput placeholder="自我介紹" formControlName="intro" required matTextareaAutosize></textarea>
结果如下:
当我们文字超过原本textarea的高度时,就会开始自动放大,当文字减少时,就会自动缩小,很有趣吧!
要使用Input的Autoomplete相关功能,首先得先加入MatAutocompleteModule
。
接下来我们来学习使用Autocomplete的功能,在这边我们希望能完成一个「国家」的输入栏位,并且能够依照输入的内容选择自动完成的清单,大致画面如下:
从画面上来看,我们需要两样东西,一个是单纯的文字输入栏位,另一个是可以选择的国家清单;文字输入栏位我们已经会了,就是一个简单的input:
<mat-form-field>
<input type="text" name="country" matInput placeholder="國家" formControlName="country" />
</mat-form-field>
而autocomplete的清单,我们可以使用<mat-autocomplete>
以及<mat-option>
的组合来建立这组清单:
<mat-autocomplete>
<mat-option *ngFor="let country of countries$ | async" [value]="country.name">
{{ country.name }}
</mat-option>
</mat-autocomplete>
国家的json档资料来源:https://gist.github.com/keeguon/2310008
我们把这个清单存到asset/countries.json
中,然后在component直接使用HttpClient
抓取这个清单的资料:
ngOnInit() {
this.countries$ = this.httpClient.get<any[]>('assets/countries.json');
}
这时候画面上还不会看到任何资料,因为我们的input还不知道要显示autocomplete的来源在哪里,我们可以在input中设定matAutocomplete
属性,指定autocomplete的来源,整个段画面程式码看起来如下:
<mat-form-field>
<input type="text" name="country" matInput placeholder="國家" formControlName="country" [matAutocomplete]="countries" />
</mat-form-field>
<mat-autocomplete #countries="matAutocomplete">
<mat-option *ngFor="let country of countries$ | async" [value]="country.name">
{{ country.name }}
</mat-option>
</mat-autocomplete>
接着再回到画面上点选国家输入栏位,就能选择国家的清单啦!
我们可以透过方向上下键来移动选单,然后按下Enter选择想要的国家。
我们已经有了一个autocomplete的清单,但这样还不太够,我们可能会希望过滤已经输入的内容,避免从冗长的清单中选取,由于我们目前使用的是ReactiveForm,因此我们可以使用valueChanges
,在资料变更时重新筛选要列出的清单:
ngOnInit() {
this.surveyForm
.get('basicQuestions')
.get('country')
.valueChanges.debounceTime(300)
.subscribe(inputCountry => {
this.countries$ = this.httpClient.get<any[]>('assets/countries.json').map(countries => {
return countries.filter(country => country.name.indexOf(inputCountry) >= 0);
});
});
}
另外,我们也可以把已经过滤的资料内容做一点修饰,依照我们输入的内容变成粗体显示,这边先加入一个
highlightFiltered(countryName: string) {
const inputCountry = this.surveyForm.get('basicQuestions').get('country').value;
return countryName.replace(inputCountry, `<span class="autocomplete-highlight">${inputCountry}</span>`);
}
接着在style.css中加入这个样式:
.autocomplete-highlight {
font-weight: bold;
background: yellow;
}
最后把画面稍微做个调整:
<mat-autocomplete #countries="matAutocomplete">
<mat-option *ngFor="let country of countries$ | async" [value]="country.name">
<span [innerHTML]="highlightFiltered(country.name)"></span>
</mat-option>
</mat-autocomplete>
再来看看结果:
可以看到清单依据我们输入的内容自动筛选出符合的项目,而且还有highlight提示,是不是很好玩啊!
我们可以透过设定<mat-autocomplete>
的displayWith
属性来指定一个function,这个function可以改变要显示的内容:
<mat-autocomplete #countries="matAutocomplete" [displayWith]="displayCountry">
<mat-option *ngFor="let country of countries$ | async" [value]="country">
<span [innerHTML]="highlightFiltered(country.name)"></span>
</mat-option>
</mat-autocomplete>
这里我们把原来的[value]
改为传入整个country物件,好让displayWith
指定的function可以透过选择的物件决定文字呈现的内容:
displayCountry(country: any) {
if (country) {
return `${country.name} / ${country.code}`;
} else {
return '';
}
}
成果如下:
可以看到在选择完国家后,透过displayWith
,我们自动为选择的内容加上了国家的编码。
<mat-option>
既然是清单型的选项资料,有个<mat-optgroup>
作为群组好像也是很合理的一件事情,Angular Material也替我们想好了,要使用一点都不难,跟在设计select的optgroup大同小异,假设我们有一组资料如下:
this.majorTechList = [
{
name: '前端',
items: ['HTML', 'CSS', 'JavaScript']
},
{
name: '後端',
items: ['C#', 'NodeJs', 'Go']
}
在画面上我们可以透过<mat-optgroup>
来显示这些群组:
<mat-form-field>
<input type="text" name="majorTech" matInput placeholder="代表技術" formControlName="majorTech" [matAutocomplete]="majorTechs" />
</mat-form-field>
<mat-autocomplete #majorTechs="matAutocomplete">
<mat-optgroup *ngFor="let techList of majorTechList" [label]="techList.name">
<mat-option *ngFor="let tech of techList.items" [value]="tech">
{{ tech }}
</mat-option>
</mat-optgroup>
</mat-autocomplete>
再来看看结果:
连这种细节都想好了,真不愧是高品质的Angular Material啊!
今天我们介绍了两个输入栏位的功能,Input与Autocomplete。
Input赋予一般的文字输入栏位新的活力!搭配MatFormField在显示资讯上也非常清楚,另外Angular Material也让我们对于错误讯息的提示时机能够有很灵活的机会去调整,可以说是非常的方便。
Autocomplete其实只是Input的延伸,但加上了一个mat-autocomplete元件,来让Input输入时能有个参考依据,Autocomplete是前端非常经典的功能,Angular Material也为这个功能做了很好的诠释,使用上也非常好上手!
文字栏位的元件其实还有一个很常用的功能,就是选择日期的功能-Datepicker,Datepicker有不少东西可以介绍,就留到明天再来聊吧!
本日的程式码GitHub:https://github.com/wellwind/it-ironman-demo-angular-material/tree/day-10-input
分支:day-10-input
autocomplete filtering 是不是一定要用reactive form?
template form 可否做相同效果?
当然可以做到同样的效果,重点是<mat-autocomplete>
的资料来源变换的时机,使用reactive form只是方便在一段typescript就可以看得清楚input变化时所做的事情,而不用另外binding change事件。
改成template form时,只需要binding input的change事件,并且过滤<mat-autocomplet>
内的资料即可。
Thank you, I think I get the general idea.
That would be great!
来自 https://ithelp.ithome.com.tw/articles/10194495
昨天我们介绍了两个常用的输入元件,分别是Input及Autocomplete,在提到Input时有介绍当<input type>
设为date时,会依照浏览器的不同产生不一样的日期显示方式,为了消除这种浏览器间的差异,我们会选择不使用原生的画面,而是自己刻(或找人家写好的)一个元件来选择日期。
而在日期选择方面,Material Design也有订出一些设计参考,同时Angular Material提供了一个Datepicker,方便我们可以快速的选择日期。
至于该如何使用呢?就让我们继续看下去吧!
在Material Design的Pickers设计指南中,针对时间和日期,都提供了一些设计的参考,主要的方向是提供一个给使用者选择日期或时间的工具,选择的方式必须直觉好理解。
在行动装置下,可以用dialog的方式显示;在萤幕比较大的画面下,可以在输入栏位下方直接显示就好。
图片来源:https://material.io/guidelines/components/pickers.html
Angular Material中目前只有Datepicker可以用来选择日期,还没有提供选择时间的元件,因此今天主要会来介绍这个选择日期的Datepicker。
老规矩,要使用Datepicker,必须先在程式中加入MatDatepickerModule
。
不过对于Datepicker来说,这样还不太够,因为跟日期有关的部分虽然JavaScript有原生的Date型别可用,但Date在不同浏览器偏偏又有不同的实作方式,而且还会遇到语系呈现的问题等等,因此比较常见的做法是使用Moment.js来处理日期相关的资讯,这部分Angular Material也都设想好了,对于日期处理的部份,我们可以选择要使用原生的处理日期方式MatNativeDateModule
或是使用moment.js处理日期的方式MatMomentDateModule
,为了让画面对日期显示有更好的支援,我们选择使用MatMomentDateModule
,不过MatMomentDateModule
没有内建在Angular Material中,需要透过npm套件安装@angular/material-moment-adapter
npm i --save @angular/material-moment-adapter moment
安装完成后再将MatMomentDateModule
加入我们共用的Module中就好啰!
跟昨天的Autocomplete一样,我们一样需要的个<input>
作为文字输入的主体,而datepicker则可以使用<mat-datepicker>
元件,我们只要在input中设定[matDatepicker]
属性及可指定input要显示的datepicker来源,另外我们加上一个<mat-datepicker-toggle>
来开关<mat-datepicker>
的显示方式。
<mat-form-field>
<input type="text" name="birthday" matInput placeholder="生日" [matDatepicker]="birthdayPicker" />
<mat-datepicker-toggle [for]="birthdayPicker" matSuffix></mat-datepicker-toggle>
<mat-datepicker #birthdayPicker></mat-datepicker>
</mat-form-field>
这边我们用了一个
matSuffix
directive,这部分会在介绍FormField时做详细的说明。
来看看结果:
一个美观大方的datepicker就产生啦!
在moment.js的强力支援下,要为Angular Material的datepicker套上中文的语系一点都不难,我们只需要在providers中为MAT_DATE_LOCALE
注入目标语系的值即可
@NgModule({
providers: [
{ provide: MAT_DATE_LOCALE, useValue: 'zh-TW' }
]
})
export class SharedMaterialModule {}
结果如下:
有了中文版,就不怕被英文不好的客户骂啦XD
datepicker会依照不同语系的设定产生不同的显示格式,这样有可能会造成不必要的混淆,我们也能够自行决定显示的格式,方法与变更语系类似,注入MAT_DATE_FORMATS
的设定即可:
export const TW_FORMATS = {
parse: {
dateInput: 'YYYY/MM/DD'
},
display: {
dateInput: 'YYYY/MM/DD',
monthYearLabel: 'YYYY MMM',
dateA11yLabel: 'YYYY/MM/DD',
monthYearA11yLabel: 'YYYY MMM'
}
};
@NgModule({
providers: [
{ provide: MAT_DATE_LOCALE, useValue: 'zh-TW' },
{ provide: MAT_DATE_FORMATS, useValue: TW_FORMATS }
]
})
export class SharedMaterialModule {}
我们分别设定了解析(parse)与显示(display)的规则,monthYearLabel
是picker左上方选择年/月时的显示格式,A11y相关的设定则是在使用萤幕朗读程式时(或mac的voice over)使用的格式
结果如下:
把语系和格式都设定成习惯的格式后,接下来我们再来看看datepicker还有些什么好玩的功能可以设定吧!
datepicker预设打开的画面会是日历形式的日期选择,我们可以将<mat-datepicker>
的startView
属性设定为"year"(预设为month),则会先出现一整年的可选月份,选择月份后,才选择日期:
<mat-datepicker #demoDatepicker startView="year"></mat-datepicker>
结果如下:
除了起始画面之外,我们也可以设定startAt
属性,来决定datepicker打开时,要从哪一天开始显示,我们可以先在component.ts中设定一个预设起始时间:
export class SurveyComponent implements OnInit {
startDate = moment(new Date(1999, 0, 1));
}
接着在画面中设定startAt
属性
<mat-datepicker #demoDatepicker [startAt]="startDate"></mat-datepicker>
就能够预设以1999年1月1号打开datepicker啦!
我们可以使用min
和max
属性,来设定一个input的最小值和最大值,当在使用datepicker时,也会根据这两个值来决定picker可选择的范围,例如我们在component中设定了时间范围:
export class SurveyComponent implements OnInit {
startDate = moment('1999-1-10');
minDate = moment('1999-1-5');
maxDate = moment('1999-1-15');
}
接着设定input的min和max属性:
<input type="text" name="birthday" matInput [min]="minDate" [max]="maxDate" placeholder="生日" [matDatepicker]="demoDatepicker" formControlName="birthday" />
<mat-datepicker-toggle [for]="demoDatepicker" matSuffix></mat-datepicker-toggle>
<mat-datepicker #demoDatepicker [startAt]="startDate"></mat-datepicker>
结果如下:
可以看到1999/01/05之前和1999/01/15之后的日期就变成灰底无法选择,这样就能固定住datepicker可以选择的范围啰。
我们也可以使用matDatepickerFilter
来指定一个过滤可用日期的function,这个function会回传true或false来告知datepicker什么时间是不可以被选择的,例如每周二和五是家庭日不可选,可以写一个filter如下:
familyDayFilter(date: moment.Moment): boolean {
const day = date.day();
return day !== 2 && day !== 5;
}
接着在画面程式码中指定这个filter:
<input type="text" name="birthday" matInput [matDatepickerFilter]="familyDayFilter" placeholder="生日" [matDatepicker]="demoDatepicker" formControlName="birthday" />
<mat-datepicker-toggle [for]="demoDatepicker" matSuffix></mat-datepicker-toggle>
<mat-datepicker #demoDatepicker [startAt]="startDate"></mat-datepicker>
成果如下:
文字输入控制项( <input type="xxx" />
)都会有原生的input和change事件,不过这些事件都只有在使用者跟input本身互动时才会触发,因此以下程式码:
<input type="text" name="birthday" matInput (input)="logDateInput($event)" (change)="logDateChange($event)" placeholder="生日" [matDatepicker]="demoDatepicker" formControlName="birthday" />
<mat-datepicker-toggle [for]="demoDatepicker" matSuffix></mat-datepicker-toggle>
<mat-datepicker #demoDatepicker [startAt]="startDate"></mat-datepicker>
得到的纪录只会是一般的InputEvent等等,不是非常清楚,如下:
若希望纪录的是真实的日期选择变化,则可以使用dateInput
和dateChange
事件,传入的事件会是MatDatepickerInputEvent<T>
如下,<T>
则看我们使用处理时间的Module是MatNativeDateModule
还是MatMomentDateModule
,如果是MatNativeDateModule
会使用Date
,MatMomentDateModule
则是Moment型别:
export class SurveyComponent implements OnInit {
logDateInput($event: MatDatepickerInputEvent<moment.Moment>) {
console.log($event);
}
logDateChange($event: MatDatepickerInputEvent<moment.Moment>) {
console.log($event);
}
}
接着把画面上的input和change事件改为dateInput
和dateChange
:
<input type="text" name="birthday" matInput (dateInput)="logDateInput($event)" (dateChange)="logDateChange($event)" placeholder="生日" [matDatepicker]="demoDatepicker" formControlName="birthday" />
<mat-datepicker-toggle [for]="demoDatepicker" matSuffix></mat-datepicker-toggle>
<mat-datepicker #demoDatepicker [startAt]="startDate"></mat-datepicker>
结果如下:
由于纪录的是Date或Moment物件,因此要做后续处理也比较容易哩!
在input中设定disabled状态其实不难,但配上datepicker则有了些不同的变化,例如以下是最简单的disabled状态,把整个input设为disabled:
this.surveyForm = new FormGroup({
basicQuestions: new FormGroup({
...
birthday: new FormControl({value: '', disabled : true})
})
});
结果如下:
另外我们也可以针对mat-datepicker-toggle
单独设定disabled状态,我们先把birthday的disabled状态改掉,再把画面调整为
原本我们的mat-datepicker-toggle
日历icon如下,是黑色可以点选的:
改变为disabled后如下:
变成了不可以点选的灰底,这时候日期选择器会无法叫出来,但input文字方块依然是可以正常输入了。
另外一种变形的做法是,我们可以把input文字栏位disable掉,但是依然保留picker可选择的状态,这么做的好处是,可以避免使用者随意输入不必要的内容,造成后续处理的麻烦;在component.ts中我们再次把birthday的状态设为disabled,这时原本是不可以输入,也没有picker可以用的,而这时候我们可以把mat-datepicker
的disabled
状态设为false
,就会变成picker可以使用的状态啰:
<input type="text" name="birthday" matInput (dateInput)="logDateInput($event)" (dateChange)="logDateChange($event)" placeholder="生日" [matDatepicker]="demoDatepicker" formControlName="birthday" />
<mat-datepicker-toggle [for]="demoDatepicker" matSuffix></mat-datepicker-toggle>
<mat-datepicker #demoDatepicker [startAt]="startDate" disabled="false"></mat-datepicker>
结果如下:
预设的行为下,datepicker是依附在input之下的,这在一般桌面上的网页没有问题,但是移到行动装置,尤其是萤幕小的触控式手机上就会显得不好操作,这时候我们可以替<mat-datepicker>
设定touchUi
,就会变成适合触控式装置的模式:
<input type="text" name="birthday" matInput (dateInput)="logDateInput($event)" (dateChange)="logDateChange($event)" placeholder="生日" [matDatepicker]="demoDatepicker" formControlName="birthday" />
<mat-datepicker-toggle [for]="demoDatepicker" matSuffix></mat-datepicker-toggle>
<mat-datepicker #demoDatepicker [startAt]="startDate" disabled="false" touchUi="true"></mat-datepicker>
成果如下:
更进阶的做法是,侦测浏览器可用的宽度,当宽度低的时候,自动切换Touch UI模式,这部分Angular Material将这样的功能切到的Angular CDK中,我们会在后面的文章另外做介绍。
<mat-datepicker>
本身就是一个component,因此我们不一定非得需要搭配<mat-datepicker-toggle>
来作切换,也能自行在程式中处理,只要去设定<mat-datepicker>
的opened
属性即可:
<mat-form-field>
<input type="text" name="birthday" matInput (dateInput)="logDateInput($event)" (dateChange)="logDateChange($event)" placeholder="生日" [matDatepicker]="demoDatepicker" formControlName="birthday" />
<mat-datepicker #demoDatepicker [startAt]="startDate" disabled="false" touchUi="true"></mat-datepicker>
</mat-form-field>
<button mat-raised-button (click)="demoDatepicker.opened = true">打開Datepicker</button>
成果如下:
不会很困难吧!
关于选择日期这件事情,一直以来都是前端的一个很大的议题,怎么让这件事情变得直觉又简单,有着不同的设计方法,Angular Material依循了Material Design中的建议,打造了一个datepicker元件,让我们能提供给使用者一个直觉大方的日期选择器。
今天我们在介绍datepicker同时,也介绍了如何整合moment.js近来,让datepicker能够发挥更强大的威力;同时这个datepicker也有许多强大的功能,甚至能对应不同装置有不同的显示方式。光是一个datepicker就有这么多东西可以设定,可以说这个datepicker真的是很重要也很实用啊!
看到这里你可能会想问,有没有选择时间的元件呢?很可惜目前Angular Material还没有实作选择时间的元件,不过既然Material Design也有针对时间元件提出建议,相信在不久的将来也是能够看到的!
本日的程式码GitHub:https://github.com/wellwind/it-ironman-demo-angular-material/tree/day-11-datepicker
分支:day-11-datepicker
想问一下datepicker 如果要用再阵列要怎去区分
<input type="text" id="rDate" name="dt_rDate[]" size="20" class="queryDate hasDatepicker">
<input type="text" id="rDate" name="dt_rDate[]" size="20" class="queryDate hasDatepicker">
<input type="text" id="rDate" name="dt_rDate[]" size="20" class="queryDate hasDatepicker">
$('.queryDate').datepicker( {showOn: 'button',buttonImage:'/images/calendar.jpg', buttonImageOnly: true});
$('.queryDate').datepicker('option', 'duration', '');
$('.queryDate').datepicker($.datepicker.regional['zh-TW']);
三个不同种类但是都是同一个dt_rDate[] 都要让使用者去各自选择日期
我现在是不管哪个选日期都是第一个input再改值
您好:这篇文章介绍的Angular Material 的datepicker,不是jquery 的datepicker 喔!
jquery 的datepicker 套件也有很多,不知道你用哪一套也不太好帮助你。
好的那我再去找看看资料谢谢
您好,想请问一下,不知道是不是版本(material:7.3.7)不同的关系导致显示的情形不同呢? 月历上每天都会出现"日"
hi!
想请教一个问题,为什么使用material的datepicker选出的日期,只有期,时间都是00:00:00有办法取得正确的时间吗?
@v830121v 我没有遇过这种状况,你可以使用stackblitz 重现这种状况吗?
@thomas550728是拿来取得「日期」的,因此时间00:00:00
是正常的喔
感谢!想想也是,它无法设定时间,当然只有00:00:00
来自 https://ithelp.ithome.com.tw/articles/10194720