属性、元素操作以及指令
普通数据
新建 news 组件,首先在 news.component.ts 文件中定义变量:
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-news', templateUrl: './news.component.html', styleUrls: ['./news.component.css'] }) export class NewsComponent implements OnInit { title = 'Hello hresh'; public name: any = 'hresh'; content: any = '<h3>Hello Java</h3>'; msg = '中国,你好'; constructor() { this.msg = '你好中国'; } ngOnInit(): void { } } 复制代码
在 html 文件中定义标签来获取定义的变量并显示:
<div> <p>news works!</p> <!--数据文本绑定--> <h3>{{title}}</h3> <hr /> <h1>{{content}}</h1> <br> <!--绑定 html--> <span [innerHTML]="content"></span> <br> <h2>{{msg}}</h2> <br> 1+1={{1+1}} </div> 复制代码
效果图如下:
图片展示
图片资源可以是本地资源,也可以从网上获取,在 html 文件中做如下配置:
<h3>引入图片</h3> <img src="assets/images/10001.png" alt="hello" /> <hr> <img [src]="picUrl" /> <img src="{{picUrl}}" /> 复制代码
本地静态资源存放位置如下:
网上图片资源链接可以在 argular01.component.ts 中定义:
public picUrl = 'https://cn.bing.com/th?id=OIP.bbd7bi181qua_NdZzguE3QHaE6&pid=Api&rs=1'; 复制代码
网页展示图如下:
模板引用变量
模板引用变量 通常是对模板中 DOM 元素的引用。它还可以引用指令(包含组件)、元素、TemplateRef 或 Web Component 。
使用井号(#)声明模板引用变量。以下模板引用变量 #phone
会在 input
元素上声明了一个 phone
变量。
<input #phone placeholder="phone number" /> <!-- lots of other elements --> <!-- phone refers to the input element; pass its `value` to an event handler --> <button (click)="callPhone(phone.value)">Call</button> 复制代码
模板引用变量的范围是整个模板。因此,不要在同一模板中多次定义相同的变量名,因为它在运行时的值将不可预测。
替代语法
你也可以用 ref-
前缀代替 #
。 下面的例子中就用把 fax
变量声明成了 ref-fax
而不是 #fax
。
<input ref-fax placeholder="fax number" /> <button (click)="callFax(fax.value)">Fax</button> 复制代码
NgFor
ngFor
指令迭代父组件的 items
属性所返回的 items
数组,并在每次迭代期间将 item
设置为该数组中的当前条目。 NgFor
指令上下文中的 index
属性在每次迭代中返回该条目的从零开始的索引。 您可以在模板输入变量中捕获 index
,并在模板中使用它。
同样在 news 组件中,首先定义数组内容:
nums: any[] = [111, 2222, 333]; public values: Array<string> = ['111', '222', '333']; userList: any[] = [ { name : 'hresh', age : 22 }, { name : 'hresh2', age : 22 }, { name : 'hresh3', age : 22 } ] cars: any[] = [ { name: '宝马', list: [ { title: 'x1', price: '30万' }, { title: 'x2', price: '30万' }, { title: 'x3', price: '30万' } ] }, { name: '奔驰', list: [ { title: 'x1', price: '30万' }, { title: 'x2', price: '30万' }, { title: 'x3', price: '30万' } ] } ] 复制代码
在 html 文件中添加内容:
<ul> <li *ngFor="let item of nums"> {{item}} </li> </ul> <br> <ul> <li *ngFor="let item of userList"> {{item.name}}---{{item.age}} </li> </ul> <br> <ul> <li *ngFor="let item of cars"> {{item.name}} <ul> <li *ngFor="let car of item.list"> {{car.title}}----{{car.price}} </li> </ul> </li> </ul> 复制代码
效果如下:
带 trackBy
的 *ngFor
比如有这样一个例子:
import{ Component } from '@angular/core'; @Component({ selector: 'trackBy-test', template: ` <ul><li *ngFor="let item of items;>{{item.name}}</li></ul> <button (click)="getItems()">Get Items</button> ` }) export class TrackByCmp{ items: any[]=[]; constructor(){ this.items = [{id:'1',name:'Tom'},{id:'2',name:'Jerry'},{id:'3',name:'Kitty'}]; } getItems(){ this.items = [{id:'1',name:'Tom'},{id:'2',name:'Jerry'},{id:'4',name:'Mac'},{id:'5',name:'John'}]; } } 复制代码
有时你会需要改变这个集合,比如从后端接口返回了新的数据。那么问题来了,Angular 不知道怎么跟踪这个集合里面的项,不知道哪些该添加哪些该修改哪些该删除。结果就是,Angular 会把该集合里的项全部移除然后重新添加。就像这样:
这样做的弊端是会进行大量的 DOM 操作,而 DOM 操作是非常消耗性能的。
那么解决方案是,为*ngFor 添加一个 trackBy 函数,告诉 Angular 该怎么跟踪集合的各项。trackBy 函数需要两个参数,第一个是当前项的 index,第二个是当前项,并返回一个唯一的标识,就像这样:
import{ Component } from '@angular/core'; @Component({ selector: 'trackBy-test', template: ` <ul><li *ngFor="let item of items;trackBy: trackByIndex">{{item.name}}</li></ul> <button (click)="getItems()">Get Items</button> ` }) export class TrackByCmp{ items: any[]=[]; constructor(){ this.items = [{id:'1',name:'Tom'},{id:'2',name:'Jerry'},{id:'3',name:'Kitty'}]; } getItems(){ this.items = [{id:'1',name:'Tom'},{id:'2',name:'Jerry'},{id:'4',name:'Mac'},{id:'5',name:'John'}]; } trackByIndex(index, item){ return index; } } 复制代码
修改之后,Angular 就知道哪些项变动了:
关于 trackBy
的更多讲解可以参考:Angular-使用好NgForOf的trackBy带来性能上的提升
NgSwitch和NgIf
首先需要在 argular01.component.ts 中定义相关数据内容:
nums: any[] = [111, 222, 333]; flag = false; order = 1; 复制代码
html 文件内容如下:
<h3>循环,显示数据的索引</h3> <div> <ul> <li *ngFor="let item of nums; let key =index"> <span *ngIf="key == 1" class="red">{{key+1}}----{{item}}</span> <span *ngIf="key != 1">{{key+1}}----{{item}}</span> </li> </ul> </div> <br> <h3>判断</h3> <div *ngIf="flag"> <p>我是一个P标签</p> </div> <div *ngIf="!flag"> <p>我是一个PP标签</p> </div> <br> <h3>NgSwitch</h3> <span [ngSwitch]="order"> <p *ngSwitchCase="1"> 1111111111 </p> <p *ngSwitchCase="2"> 2222222222222 </p> <p *ngSwitchDefault> 00000000000 </p> </span> 复制代码
上述内容除了介绍 ngIf 和 ngSwitch 的用法,还提到关于循环索引的定义(索引从0开始),同 ngIf 配合使用。
网页效果图如下:
NgClass和NgStyle
用 ngClass
同时添加或删除几个 CSS 类。
<div> <div [ngClass]="currentClasses">This div is initially saveable, unchanged, and special.</div> <div [ngClass]="isSpecial ? 'special' : ''">This div is special</div> <div [class]="isSpecial ? 'special2' : ''">This div is special</div> </div> 复制代码
考虑一个 setCurrentClasses()
组件方法,该方法设置一个组件属性 currentClasses
,该对象具有一个根据其他三个组件属性的 true
/ false
状态来添加或删除三个 CSS 类的对象。该对象的每个键(key)都是一个 CSS 类名。如果要添加上该类,则其值为 true
,反之则为 false
。
home2.component.ts
canSave = true; isUnchanged = true; isSpecial = true; constructor() { } ngOnInit(): void { this.setCurrentClasses(); } setCurrentClasses() { this.currentClasses = { 'saveable': this.canSave, 'modified': !this.isUnchanged, 'special': this.isSpecial }; } 复制代码
CSS 样式:
.saveable{ background-color: blue; } .modified{ font-size: 21px; } .special{ font-weight: 200; } .special2{ font-weight: 200; } 复制代码
页面测试:
从上述例子可以看出,当添加单个类时,使用类绑定和 Ngclass 效果是一致的。所以官方文档推荐: 要添加或删除单个类,请使用类绑定而不是 NgClass
。
使用 NgStyle
根据组件的状态同时动态设置多个内联样式。
<div [ngStyle]="currentStyles"> This div is initially italic, normal weight, and extra large (24px). </div> <div [style.font-size]="isSpecial ? 'x-large' : 'smaller'"> This div is x-large or smaller. </div> 复制代码
下面的例子是一个 setCurrentStyles()
方法,它基于该组件另外三个属性的状态,用一个定义了三个样式的对象设置了 currentStyles
属性。
currentStyles: any = {}; canSave = true; isUnchanged = true; isSpecial = true; constructor() { } ngOnInit(): void { this.setCurrentStyles(); } setCurrentStyles() { // CSS styles: set per current state of component properties this.currentStyles = { 'font-style': this.canSave ? 'italic' : 'normal', 'font-weight': !this.isUnchanged ? 'bold' : 'normal', 'font-size': this.isSpecial ? '24px' : '12px' }; } 复制代码
页面测试:
同 ngClass 一样,官方文档同样推荐设置单个样式值采用样式绑定,设置多个内联样式,请使用 NgStyle
指令 。
管道
管道是格式化字符串、金额、日期和其它显示数据的好办法
Angular 自带了很多管道,比如 date 管道和 currency 管道,完整的列表参见 Pipes API 列表。你也可以自己定义一些新管道。
在 birthday.component.ts
文件中设置如下:
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-birthday', templateUrl: ' <p>The hero's birthday is {{ birthday | date:format }}</p> <button (click)="toggleFormat()">Toggle Format</button> ' }) export class BirthdayComponent implements OnInit { birthday = new Date(1988, 3, 15); // April 15, 1988 toggle = true; // start with true == shortDate constructor() { } ngOnInit(): void { } get format() { return this.toggle ? 'shortDate' : 'fullDate'; } toggleFormat() { this.toggle = !this.toggle; } } 复制代码
网页展示效果:
安全导航运算符( `?` )和空属性路径
Angular 安全导航运算符 ?
可以对在属性路径中出现 null
和 undefined
值进行保护。在这里,如果 item
为 null
,它可以防止视图渲染失败。
<p>The item name is: {{item?.name}}</p> 复制代码
如果 item
为 null
,则视图仍然渲染,但显示的值为空白;您只会看到 “The item name is:” ,后面没有任何内容。
考虑接下来这个带有 nullItem
的例子。
The null item name is {{nullItem.name}} 复制代码
由于没有安全导航运算符,并且 nullItem
为 null
,因此 JavaScript 和 Angular 会引发空指针错误并中断 Angular 的渲染过程:
content_copyTypeError: Cannot read property 'name' of null. 复制代码
但是,有时在某些情况下,属性路径中的 null
值可能是可接受的,尤其是当该值开始时为空但数据最终会到达时。
使用安全导航运算符 ?
,当 Angular 表达式遇到第一个空值时,它将停止对表达式的求值,并渲染出无错误的视图。
绑定语法
数据绑定是一种机制,用来协调用户可见的内容,特别是应用数据的值。 虽然也可以手动从 HTML 中推送或拉取这些值,但是如果将这些任务转交给绑定框架,应用就会更易于编写、阅读和维护。 您只需声明数据源和目标 HTML 元素之间的绑定关系就可以了,框架会完成其余的工作。
Angular 提供了多种数据绑定方式。绑定类型可以分为三类,按数据流的方向分为:
- 从数据源到视图
- 从视图到数据源
- 双向:视图到数据源到视图
绑定类型与绑定目标
数据绑定的目标是 DOM 中的对象。 根据绑定类型,该目标可以是 Property 名(元素、组件或指令的)、事件名(元素、组件或指令的),有时是 Attribute 名。下表中总结了不同绑定类型的目标。 关于这一部分会结合例子进行演示,没有固定篇幅进行讲解,详细内容可以参考:Angular模块语法