Angular 模板语法大纲
- 何为模板
- 模板中的表达式
- 模板中的绑定
- 模板中的内置指令
- 模板中的变量
学习 Angular 最基础的就是组件,组件也是 Angular 框架的特色。那组件中自然也少不了模板。为了加深自己对这块的理解,专门做了一个规整。
一、何为模板
模板,百度百科是这样说的:模板,是指作图或设计方案的固定格式,有时也指DNA复制或转录时,用来产生互补链的核苷酸序列。模板是将一个事物的结构规律予以固定化、标准化的成果,它体现的是结构形式的标准化
当然,百度的解释对我们来讲显然没有什么卵用。
在我们 Angular 中,一般说的是 html 模板,也就是组件中对应引入的 html 文件或一段 html 语句。好,那我们就来说说这个 html 模板中都有哪些语法。
二、模板中的表达式
说到表达式那就是双花括号了 {{ }} 。Angular 官方叫做插值表达式。
它用在哪?
<p>{{name}}</p><!--可以放在这:标签之间-->
<p class="{{isBlue}}"></p><!--也可以放在这:属性的值-->
→
那它能干什么?
1. 解析组件中的属性
2. 运算简单的运算符
3. 执行方法
<p>{{name}}</p> <!--解析绑定 组件.ts 中的属性;当然也可以是上下文-->
<p>{{1 + 1}}</p> <!--简单运算-->
<p>{{getName()}}</p> <!--执行方法-->
→
说到解析绑定通常是 组件实例 的属性,这个没什么解释,当然也可以是模板内的局部变量,啥是局部变量,后面有解释。
当然,官方中还有个模板表达式,这个就不说了,容易让人迷糊。所以我不打算叫这个名字。
三、模板中的绑定
说到绑定,即数据绑定。那有几种绑定方法?
1. {{ }} 花括号中的解析绑定
2. 属性绑定
3. 事件绑定
4. 双向绑定
花括号中的解析绑定
上面说到花括号可以解析组件中的属性,从而达到从组件到视图的单向绑定。
// app.component.ts
public name:string = "张三";
// app.component.html
<div>{{name}}</div>
属性绑定
属性绑定,顾名思义:类似于html属性的绑定。可以拿这个去理解一下这个名词,但是它不是。
属性绑定写法:html 标签中: [xx] = “yy” 。
用法:1、html 原生标签上面的属性绑定。2、Angular模板内置指令的属性绑定。3、自定义标签(子组件标签)上面的自定义属性绑定。
- 我们先来说 html 原生标签上面的属性绑定:
原生标签上面的属性绑定,可以联想到,原生标签现有的属性,比如:src、title、disabled等。来绑定到这上面,从而控制该 html 标签。但不是所有的html属性都属于简单的属性绑定,像class、style等就属于内置属性型指令,如果使用会覆盖原来的 html 的 class 属性,且值为 undefined 。
先举例说明:
// app.component.ts
public srcUrl:string = "http://www.baidu.com/123.png";
// app.component.html
<img [src]="srcUrl" />
可以看出,是将属性的值绑定到组件的某一个属性。所以也有人喜欢叫值绑定
- Angular模板内置指令的属性绑定:
Angular 在模板中内置了两种指令:属性型指令、结构性指令。这里我们说属性绑定,先说下它的属性型指令(结构型指令下面说)。
既然是属性绑定,用法是一样的,也是中括号括起来,只是这里面的属性 不是原生标签的属性了,而是指令:ngClass\ngStyle等
举例说明 ngClass :
<!-- 单个 class 绑定,绑定一个布尔值: toColor 为 true 时添加 class=whiteColor -->
<div [class.whiteColor]="toColor"></div>
<!-- 多个 class 绑定,绑定一个对象: setStyle 对象里面的属性为class名,当对象的属性的值为 true 时添加对应的class -->
<!--app.conponent.html-->
<div [ngClass]="setStyle"></div>
<!--app.conponent.ts-->
public toColor:boolean = true;
public setStyle: any={};
this.setStyle = {
whiteColor: true, // 只添加 whiteColor css类
fontSize12: false
}
举例说明 ngStyle :
<!--绑定单个内联样式,指令属性的值为具体的样式的值-->
<div [style.color]="oWhite">122</div>
<div [style.fontSize.px]="oFont">2323</div>
<!--绑定多个内联样式,指令属性的值为一个对象,该对象的属性为样式名,值为样式具体的值-->
<div [ngStyle]="objStyle"></div>
// app.component.ts
public oWhite:string = "red";
public oFont:number = 23;
public objStyle:any = {};
this.objStyle = {
"color": "red",
"size": "24px"
}
- 自定义标签(子组件标签)上面的自定义属性绑定:
既然标签是自定义的,那这上面基本就没有原生标签上面的那些属性,所以,我们的属性也都是自定义的,一般是用来向自定义标签(也代表子组件)传递数据的,我们叫它写入属性或输入属性。
举个例子理解下:
// 父组件 app.component.ts
public myName:string = "张三";
// 父组件 app.component.html
<app-child [name]="myName"></app-child>
// 子组件 child.component.ts
@Input() public name:string; // 子组件用 @Input() 来接收数据
ngOnInit(){
console.log(name); //张三
}
@Input() 的用法会在组件通讯那篇文章中说,这里先明白下输入属性的含义。
还有,我们的属性绑定还可以写成:bind-src=”srcUrl” 。这里便说明了,它不单单是 html 的原生属性,因为原生属性没有 bind-src 这个属性。这里它是 html 的 porperty 属性。
事件绑定
事件绑定,顾名思义:通过绑定一个事件来做一些东西。一般都是触发一个事件来执行某个方法。事件绑定与属性绑定类似,它们都不是原生的事件方法,都是 Angular 自己封装的。
这里我们有两种:1、html 原生标签的普通事件绑定。2、自定义标签(代表子组件)的自定义事件绑定。
事件绑定写法:html 标签中 (x)=”y” 。
- html 原生标签的普通事件绑定:
普通事件绑定,就是平常我们用的事件,一般都能用,像click、keyup、change等等。
话不多了,举例一看就知道:
<!--点击执行某个方法-->
<button (click)="getName()"></button>
<!--键盘弹起执行某个方法-->
<input (keyup)="getName()">
- 自定义标签(代表子组件)的自定义事件绑定:
这里的自定义事件绑定与前面的自定义事件绑定类似,都是用在子组件的自定义标签上面,这回这个不是输入了,而是输出,即从子组件里面传递出数据给父组件,需要配合子组件的 @Output() 装饰器(@Output() 也不在这说,这里只是让大家了解事件绑定)来使用。
流程是:子组件定义一个事件派发器,通过某个方法来派发刚刚定义的事件,这时父组件模板上面的自定义事件就是子组件派发过来的,收到事件后来执行某个方法或干点别的事情。
看例子:
// app.component.html
<app-child (getName)="showName()"></app-child>
// child.component.ts
@Output() getName = new EventEmitter<string>();
// 点击某个按钮执行 toName() 方法,这时父组件会接收到该事件,然后执行父组件的 showName() 方法
toName(){
this.getName.emit();
}
双向绑定
说完了属性绑定与事件绑定,现在说一下双向绑定。双向绑定其实就是前面两者的终极合璧。
双向绑定的用法:html 标签内 [(x)]=”y” 。
在 AngularJS 中双向绑定一般只有一种用法–用于表单。但是Angular中有了组件,使得我们的双向绑定又有了一种方法。
1、组件的双向绑定
2、表单的双向绑定
- 组件的双向绑定:
组件的双向绑定其实是用于父子组件的,就是比如:某个属性无论在子组件变化还是在父组件变化,父子组件的视图都会发生变化。这应该不难理解。
刚刚说了它是属性绑定与事件绑定的终极合璧,是怎么合的?就是自定义属性与自定义事件合为一个,所以它只是用在自定义标签上面,那它的作用也就是父子组件的交互,那我们来看看是如何双向绑定的?
栗子在这:
// app.component.ts
public fontSizePx: number = 14; // 初始化 fontSizePx 属性
// app.component.html
<app-child [(size)]="fontSizePx"></app-child>
<div [style.font-size.px]="fontSizePx">父组件的模板字体{{fontSizePx}}号</div>
// child.component.ts
@Input() size: number | string;
@Output() sizeChange = new EventEmitter<number>();
toBig(){
this.sizeChange.emit(30);
}
// child.component.html
<button (click)="toBig()">变大</button> <!--点击按钮父子组件的字体都变为30号,说明子组件操作字号也绑定到父组件了-->
<div [style.font-size.px]="size">子组件的模板字体{{size}}号</div> <!--未设置字号,初始化便是14号,说明是父组件设置的,绑定到了子组件-->
仔细看看,咦…视乎有点怪怪的,那这样说是自定义的属性与自定义的事件名字需要一样喽,其实不是。这样双向绑定对命名稍微有点限制,就是比如说自定义属性名字为:name,那自定义的事件名字必须为:nameChange。才能完成双向绑定,即简写。
那知道了这个逻辑,我们也可以把双向绑定给拆开了。
// app.component.html
<app-child [size]="fontSizePx" (sizeChange)="fontSizePx=$event"></app-child> <!--这里的事件触发后就不是执行某个方法了,而是一个赋值绑定-->
- 表单的双向绑定
对于双向绑定,可能用的最多的也就是表单这块了。业务场景便是:既要回显数据,同时可能需要修改数据。
表单的双向绑定,用到 ngModel 指令,这个指令不是核心模块里面的,需要在模块中引入 FormsMdule 模块
// app.component.ts
imort {FormsModule} from '@angular/forms';
引入之后就可以使用 ngModel 指令了,接下来就用例子讲话:
// app.component.html
<input [(ngModel)]="myName" (input)="getName()">
<p>{{getName}}</p>
// app.component.ts
public myName: string = "张三"; // 初始化数据绑定到视图
// 写个方法,当文本框改变时,取一下 myName 看是否绑定到ts文件里面
getName():void{
console.log(myName);
}
执行后,既可以从页面看到绑定的值,也可以从控制台看到绑定的值。
三、模板中的内置指令
当然除了模板中内置了几个指令,你也可以自定义指令,关于自定义指令,这里不再说。这里我们说模板中内置的几个指令。
模板的内置指令有两种:属性型指令、结构型指令
属性型指令这里就不在说了,上面已经说了,就是ngClass\ngStyle等等
下面我们说一下结构型指令:ngIf\ngFor\ngSwitch
结构型指令的用法不同于属性型指令,比如:它是在 html 标签内 *ngIf=”xx”
- ngIf 指令
通过名字也能知道,它是用来做判断。如果值为 true 显示当前的标签,反之,则删除该标签,是删除不是隐藏(display:none)。
看一个点击轮换的例子:
// app.component.ts
public isShow:boolean = true;
changeState(){
this.isShow = !this.isShow
}
// app.component.html
<div *ngIf="isShow">出现了</div>
<button (click)="changeState()">消失\出现</button>
- ngFor 指令
这个呢就是做for循环的,没什么说的,把例子列出来:
// app.component.ts
public heros:Array<string> = ['张三','李四','王五'];
// app.component.html
<ul>
<li *ngFor="let hero of heros">{{hero}}</li> //会把所有的数据都遍历出来生成对应的li标签
</ul>
- ngSwitch 指令
这个也直接列代码吧,虽然不是很常用:
// app.component.ts
public mapStatus:string="张三"; // 初始化显示的数据
// app.component.html
<div [ngSwitch]="mapStatus">
<p *ngSwitchCase="'张三'">张三</p> // 显示该项
<p *ngSwitchCase="'李四'">李四</p>
<p *ngSwitchDefault>小明</p> // 没有数据,显示该项
</div>
四、模板中的变量
在 Angular 中,模板内部是可以直接使用变量,这个变量并不是组件实例中定义的属性,而是在模板的 html 标签上面直接定义变量。
这里有两种定义变量的方式:
1、输入变量
2、引用变量
输入变量
对于输入变量其实我们已经用过了,在上面的 ngFor 指令中。
<ul>
<li *ngFor="let hero of heros">{{hero}}</li>
</ul>
这个 hero 就是我们在模板中使用 let 直接定义的变量。它只能在 ul 标签里面使用。很简单,不过一般也只用普通 html 标签上面。
引用变量
引用变量也是在 html 标签上面直接定义。不过它是使用 # 号来定义的。
模板引用变量通常用来引用模板中的某个DOM元素,比如:
<!--引用变量代表 input 标签-->
<input #phone type="text">
<!--取出input标签里面的value值传到方法里面-->
<button (click)="callPhone(phone.value)">Call</button>
另外,它还可以引用Angular组件或指令。
参考资料:angular 文档: https://angular.cn/guide/template-syntax
注:本文章持续更新
原文发自 seebin 博客:http://blog.seebin.com/2017/08/16/angular-template/