属性、元素操做以及指令普通数据图片展现模板引用变量NgForNgSwitch和NgIfNgClass和NgStyle管道安全导航运算符( `?` )和空属性路径绑定语法绑定类型与绑定目标事件普通点击事件表单事件双向数据绑定$event 和事件处理语句Form表单搜索TodoList(待办事项和已完成事项)javascript
新建 news 组件,首先在 news.component.ts 文件中定义变量:css
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 文件中定义标签来获取定义的变量并显示: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>
复制代码
效果图以下:java
图片资源能够是本地资源,也能够从网上获取,在 html 文件中作以下配置:nginx
<h3>引入图片</h3>
<img src="assets/images/10001.png" alt="hello" />
<hr>
<img [src]="picUrl" />
<img src="{{picUrl}}" />
复制代码
本地静态资源存放位置以下:web
网上图片资源连接能够在 argular01.component.ts 中定义:json
public picUrl = 'https://cn.bing.com/th?id=OIP.bbd7bi181qua_NdZzguE3QHaE6&pid=Api&rs=1';
复制代码
网页展现图以下:bootstrap
模板引用变量 一般是对模板中 DOM 元素的引用。它还能够引用指令(包含组件)、元素、TemplateRef 或 Web Component 。 后端
使用井号(#)声明模板引用变量。如下模板引用变量 #phone
会在 input
元素上声明了一个 phone
变量。 api
<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
指令迭代父组件的 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带来性能上的提高
首先须要在 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
同时添加或删除几个 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模块语法
首先修改 html 文件:
<h3>事件</h3>
<button (click)="run()">执行事件</button>
<br>
<br>
<button (click)="getData()">获取数据</button>
<br>
<br>
<strong>{{title}}</strong>
<br>
<br>
<button (click)="setData()">设置数据</button>
<br>
<br>
<button (click)="runEvent($event)" id="btn">执行方法获取事件对象</button>
<br>
复制代码
而后在 argular01.component.ts 文件中添加实现方法
title = '这是一个主题';
keywords = '这是一个input'
run() {
alert('hello');
}
constructor() { }
ngOnInit(): void {
}
getData() {
alert(this.title);
}
setData() {
this.title = '新的主题';
}
runEvent(e) {
var dom = e.target;
dom.style.color = 'red';
}
复制代码
网页展现效果以下:
html 文件:
<h3>表单事件 事件对象</h3>
<!--<input type="text" (keydown)="keydown()">-->
<br>
<input type="text" (keydown)="keydown($event)">
<br>
<input type="text" (keyup)="keyup($event)" >
复制代码
而后在 argular01.component.ts 文件中添加实现方法
keydown(e) {
console.log(e.target.value);
}
keyup(e) {
if (e.keyCode == 13) {
console.log('敲了一下回车');
}
}
复制代码
网页展现效果以下:
补充语句与事件绑定的例子,语句上下文能够引用模板自身上下文中的属性,在上面例子中把模板的$event对象传给了组件中的事件处理方法,还能够将模板输入变量 (let key
)和模板引用变量 (#inputDom
) 传到组件方法中。
<input type="text" #inputDom (input)="getData2(inputDom.value)" />
<br>
<div>
<ul>
<li *ngFor="let item of nums; let key =index">
<span>{{key+1}}----{{item}}</span>
<button (click)="delete(key)">X</button>
</li>
</ul>
</div>
复制代码
事件方法定义以下:
getData2(data: any) {
console.log(data);
}
delete(key) {
this.nums.splice(key, 1);
}
复制代码
页面测试:
双向绑定会作两件事:
设置特定的元素属性。
监听元素的变动事件。
Angular 为此提供了一种特殊的双向数据绑定语法 [()]
。[()]
语法将属性绑定的括号 []
与事件绑定的括号 ()
组合在一块儿。
首先在 app.module.ts 里面引入 NgModule 并声明。
// 浏览器解析的模块
import { BrowserModule } from '@angular/platform-browser';
// Angular核心模块
import { NgModule } from '@angular/core';
import {FormsModule} from '@angular/forms';
// 根组件
......
// @NgModule装饰器,@NgModule接受一个元数据对象,告诉 Angular 如何编译和启动应用
@NgModule({
declarations: [// 配置当前项目运行的组件
AppComponent, NewsComponent, Argular01Component, FormComponent, SearchComponent
],
imports: [// 配置当前模块运行依赖的其余模块
BrowserModule,
FormsModule
],
providers: [StorageService],
bootstrap: [AppComponent]
})
export class AppModule { }
复制代码
html 文件内容:
<h3>双向绑定</h3>
<p><input type="text" [(ngModel)]="keywords"></p>
<span>{{keywords}}</span>
<br>
<br>
<span><button (click)="upkeywords()">修改数据</button></span>
复制代码
最后在 argular01.component.ts 定义变量和方法。
keywords = '这是一个input';
upkeywords() {
this.keywords = '改变后的数据';
}
复制代码
网页展现效果:
关于 input 框双向数据绑定,在上面介绍的 (input)="getData2(inputDom.value)"
方法,修改一下也能够实现一样的效果。
html 文件:
<p>input数据绑定:<input [value]="keywords"
(input)="keywords=$event.target.value" ></p>
<span>{{keywords}}</span>
复制代码
上面的代码在把输入框的 value
属性绑定到 name
属性。 要监听对值的修改,代码绑定到输入框的 input
事件。 当用户形成更改时,input
事件被触发,并在包含了 DOM 事件对象 ($event
) 的上下文中执行这条语句。
要更新 name
属性,就要经过路径 $event.target.value
来获取更改后的值。
页面测试:
新建一个组件:
ng g component components/form
复制代码
首先在 app.module.ts 里面引入 NgModule 并声明。
一、form.component.html
<h2>人员登记系统</h2>
<!--讲解表单 input、checkbox、radio、select、textarea实如今线预定功能-->
<div class="people_list">
<ul>
<li>
姓 名:
<input type="text" [(ngModel)]="peopleInfo.username" id="username" class="form_input">
</li>
<li>
性 别:
<input type="radio" value="1" name="sex" id="man" [(ngModel)]="peopleInfo.sex"> <label for="man">男</label>
<input type="radio" value="2" name="sex" id="woman" [(ngModel)]="peopleInfo.sex"> <label for="woman">女</label>
</li>
<li>
城 市:
<select [(ngModel)]="peopleInfo.city">
<option *ngFor="let item of peopleInfo.cities">
{{item}}
</option>
</select>
</li>
<li>
爱 好:
<span *ngFor="let item of peopleInfo.hobbies;let key=index" >
<input type="checkbox" [id]="'check'+key" [(ngModel)]="item.checked"><label [for]="'check'+key">{{item.title}}</label>
</span>
</li>
<li>
备 注:
<textarea [(ngModel)]="peopleInfo.remark" cols="30" rows="2"></textarea>
</li>
<br>
<button (click)="getData()">获取表单的值</button>
<pre>
{{peopleInfo | json}}
</pre>
</ul>
</div>
复制代码
二、form.component.css
ul,ol{
list-style-type: none;
}
*{
margin: 0px;
padding:0px;
}
h2{
text-align: center;
}
.people_list{
width: 400px;
margin: 40px auto;
padding: 20px;
border: 1px solid #eeeeee;
}
.people_list li{
height: 50px;
line-height: 50px;
}
.form_input{
width: 300px;
height: 28px;
}
复制代码
三、form.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-form',
templateUrl: './form.component.html',
styleUrls: ['./form.component.css']
})
export class FormComponent implements OnInit {
peopleInfo: any = {
username: '',
sex: '1',
cities: ['北京', '上海', '深圳'],
city: '上海',
hobbies: [
{
title: '吃饭',
checked: false
},
{
title: '睡觉',
checked: false
},
{
title: '写代码',
checked: true
}
],
remark: ''
}
constructor() { }
ngOnInit(): void {
}
getData() {
console.log(this.peopleInfo);
}
}
复制代码
四、网页展现效果
五、小结
对于性别单选和爱好多选框,勾选时前台发生了什么变化,双向数据绑定了什么样的数据。
上面动图中注意观察 ng-reflect-model 值的变化。
新建一个组件:
ng g component components/search
复制代码
首先在 app.module.ts 里面引入 NgModule 并声明。
一、search.component.html
<h2>search</h2>
<div class="search">
<input type="text" [(ngModel)]="keyWord" (keyup)="keyup($event)"> <button (click)="search()">搜索</button>
<hr>
<ul>
<li *ngFor="let item of keyWordsOld;let key=index"> {{item}} ----- <button (click)="delete(key)">X</button></li>
</ul>
</div>
复制代码
二、search.component.ts
keyWord: any = '';
keyWordsOld: any[] = [];
keyup(e) {
if (e.keyCode === 13){
if (this.keyWordsOld.indexOf(this.keyWord) === -1) {
this.keyWordsOld.push(this.keyWord);
}
this.keyWord = '';
}
}
search() {
if (this.keyWordsOld.indexOf(this.keyWord) == -1) {
this.keyWordsOld.push(this.keyWord);
}
this.keyWord = '';
}
delete(key) {
this.keyWordsOld.splice(key, 1);
}
复制代码
三、网页展现效果
结合咱们平常使用淘宝京东的习惯,搜索记录都会保留下来,这就涉及到数据持久化,后续会整合讲解。
练习双向绑定来实现代办事项和已完成事项的转变。
一、search.component.html
<h2>搜 索todoList</h2>
<div class="search">
<input type="text" [(ngModel)]="product" (keyup)="add($event)" >
<hr>
待办事项
<ul>
<li *ngFor="let item of products;let key=index" [hidden]="item.status == 1">
<input type="checkbox" [(ngModel)]="item.status">{{item.status}} ---- {{item.title}}
----- <button (click)="deleteWay(key)">X</button>
</li>
</ul>
<hr>
已办事项
<ul>
<li *ngFor="let item of products;let key=index" [hidden]="item.status == 0">
<input type="checkbox" [(ngModel)]="item.status" >{{item.status}} ---- {{item.title}}
----- <button (click)="deleteWay(key)">X</button>
</li>
</ul>
<hr>
<div>
<pre>
{{products | json}}
</pre>
</div>
</div>
复制代码
二、search.component.ts
product: any = '';
products: any[] = [];
add(e) {
// tslint:disable-next-line:triple-equals
if (e.keyCode == 13) {
if (!this.equalProduct(this.products, this.product)) {
this.products.push({
title: this.product,
status: 0
});
this.product = '';
} else {
alert('数据已存在');
this.product = '';
}
}
}
deleteWay(key) {
this.products.splice(key, 1);
}
equalProduct(products: any[], value: any) {
if (!value || value === '') {
return false;
}
// tslint:disable-next-line:prefer-for-of
for (let i = 0; i < products.length; i++) {
// tslint:disable-next-line:triple-equals
if (products[i].title == value) {
return true;
}
}
return false;
}
复制代码
三、网页展现效果