Angular 基础知识规整之模板语法

发布日期 目录 Angular
Angular 模板语法大纲
  1. 何为模板
  2. 模板中的表达式
  3. 模板中的绑定
  4. 模板中的内置指令
  5. 模板中的变量

Angular4.x

学习 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”

  1. 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>
  1. ngFor 指令

这个呢就是做for循环的,没什么说的,把例子列出来:

// app.component.ts
public heros:Array<string> = ['张三','李四','王五'];

// app.component.html
<ul>
    <li *ngFor="let hero of heros">{{hero}}</li>   //会把所有的数据都遍历出来生成对应的li标签
</ul>
  1. 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/

发表评论

邮箱地址不会被公开。