Angular 组件怎么检测Input为引用类型的变化 ?
Angular 组件 和 外界通信最基本的方式有2种,外界出入组件,使用Input 属性,组件传出数据,使用Output属性。Input 的属性的变化可以在ngOnChanges 钩子函数中检测到,但是如果Input属性的类型不是原始类型,如数组,数组的单个成员变化,如使用Array.splice/push 等方法改变了输入属性,改怎么监听呢?
监听 Array成员的改变
一般数组成员的改变是由一些常用的方法push splice pop, [index] = 操作引起 ,怎么监听这些操作导致数组的改变呢? 利用Angular 内置变检类IterableDiffers 来实现
实现步骤:
- 构造函数中注入 IterableDiffers 实例
// 产品Differ
private productsDiffer: IterableDiffer<any>;
constructor(private iterableDiffers:IterableDiffers) {}
- 创建一个IterableDiffer实例
ngOnInit(): void {
this.productsDiffer = this.iterableDiffers.find(this.products).create();
}
- 检测变化
ngDoCheck(): void {
// IterableDiffer.diff
const diff = this.productsDiffer.diff(this.products);
if(diff){
console.log('products is changed in ngDoCheck');
}
}
trackByFn
如果想监听第三级,也就是数组对象的属性的变化,以上步骤还需要调整,create 方法转入trackByFn
// 新增
private trackByFn(index: number, item: any) {
return item.name;
}
//修改
ngOnInit(): void {
this.productsDiffer = this.iterableDiffers.find(this.products)
.create(this.trackByFn);
}
测试实例代码
app-shop
import { Component, OnInit } from '@angular/core';
import { products } from './data';
@Component({
selector: 'app-shop',
// templateUrl: './shop.component.html',
template: `
<app-product-list [products]="products"></app-product-list>
<p>
<button (click)="test1()">[index]=</button>
<button (click)="test2()">push</button>
<button (click)="test()">reset</button>
<button (click)="test3()">change object attribute</button>
</p>
`,
})
export class ShopComponent implements OnInit {
public products = [];
constructor() { }
ngOnInit(): void {
this.products = [...products];
}
// 使用数组索改变数组
test1():void {
this.products[1]= {
name:'realme',
description:'a new brand phone',
price: 499
}
}
// 使用push 方法
test2():void {
this.products.push({
name:'xiaomi',
description:'you will love it',
price: 549
});
}
// 重新赋值
test(): void {
this.products =[...products];
}
// 更深一级,改变对象的某一个属性
test3(): void {
this.products[0].name = 'iphone pro'
}
}
app-product-list
import {
Component,
Input,
IterableDiffer,
IterableDiffers,
OnInit,
SimpleChanges
} from '@angular/core';
// import { products } from '../data';
@Component({
selector: 'app-product-list',
// templateUrl: './product-list.component.html',
template:`
<h2>Products</h2>
<div *ngFor="let product of products;index as productId">
<h3>
<a [title]="product.name + ' details'" >
{{ product.name }}
</a>
</h3>
<p *ngIf="product.description">
Description: {{ product.description }}
</p>
<button (click)="share()">
Share
</button>
</div>
`,
})
export class ProductListComponent implements OnInit {
@Input() products: Array<any> = [];
// 产品Differ
private productsDiffer: IterableDiffer<any>;
constructor(private iterableDiffers: IterableDiffers) {}
ngOnInit(): void {
this.productsDiffer = this.iterableDiffers.find(this.products)
.create(this.trackByFn);
}
//
ngDoCheck(): void {
// IterableDiffer.diff
const diff = this.productsDiffer.diff(this.products);
if (diff) {
console.log('products is changed in ngDoCheck');
}
}
ngOnChanges(changes: SimpleChanges): void {
if (changes['products']) {
console.log('products changed in ngOnChanges');
}
}
private trackByFn(index: number, item: any) {
return item.name;
}
share(): void {
window.alert('The product has been shared!');
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。