Angular 组件怎么检测Input为引用类型的变化 ?

袭人
• 阅读 1873

Angular 组件怎么检测Input为引用类型的变化 ?

Angular 组件 和 外界通信最基本的方式有2种,外界出入组件,使用Input 属性,组件传出数据,使用Output属性。Input 的属性的变化可以在ngOnChanges 钩子函数中检测到,但是如果Input属性的类型不是原始类型,如数组,数组的单个成员变化,如使用Array.splice/push 等方法改变了输入属性,改怎么监听呢?

监听 Array成员的改变

一般数组成员的改变是由一些常用的方法push splice pop, [index] = 操作引起 ,怎么监听这些操作导致数组的改变呢? 利用Angular 内置变检类IterableDiffers 来实现

实现步骤:

  1. 构造函数中注入 IterableDiffers 实例
// 产品Differ
 private productsDiffer: IterableDiffer<any>;
constructor(private iterableDiffers:IterableDiffers) {}
  1. 创建一个IterableDiffer实例
ngOnInit(): void {
    this.productsDiffer = this.iterableDiffers.find(this.products).create();
 }
  1. 检测变化
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!');
  }

}
点赞
收藏
评论区
推荐文章
Easter79 Easter79
4年前
vue 纯数字input
最近项目中需要实现一个元和分的转换,要求存储使用分,显示使用元。意外发现了一个实现input只能输入纯数字的方案computed:{money:{//paycontent组件金额以分为单位,当前组件以元为单位,因此需要转换get(){
CuterCorley CuterCorley
4年前
uni-app入门教程(4)组件的基本使用
@toc前言本文主要介绍了uniapp中的组件,包括四大类:基础组件(scrollview、swiper、text等)、表单组件(button、checkbox、input等)、导航组件navigator和页面传参、媒体组件(audio、image和video等),详细说明了这些组件的常用属性和方法,并进行使用举例和演示。一、基础组件组件是视
LinMeng LinMeng
5年前
html5的input类型(type)和所有属性详解
先总结input的所有属性required:标记一个字段是否为必须。如果一个字段被标记为required"required"(严格模式下),或者required(宽松模式下)并且这个字段的值为空,或者填入的值是无效值,那么这个表单不能提交。什么是无效值?看pattern属性pattern:该属性包含了一个JavaScript风格的正则表达式,输
Stella981 Stella981
4年前
AngularJS 中 Controller 之间的通信
用Angular进行开发,基本上都会遇到Controller之间通信的问题,本文对此进行一个总结。在Angular中,Controller之间通信的方式主要有三种:1)作用域继承。利用子Controller控制父Controller上的数据。(父Controller中的数据要为引用类型,不能是基本类型,原因参见 Angula
Stella981 Stella981
4年前
Angular 1 深度解析:组件化编程
angular1也要面向组件编程前端组件化是前端开发模式中一个不可逆转的趋势,三大主要前端框架angular2reactvue都不约而同的把组件化编程作为自己的一大卖点,angular1作为一个历史相对悠久的框架,在私生子angular2的推动下,终于也搭上了组件化编程的末
Stella981 Stella981
4年前
ReactNative遇到的坑总结(持续更新)
问题:在Android中input组件,文字会有遮挡在Android中,input组件默认会有内边距,所以把padding改为0可以解决问题问题:在Android中input组件,底部会有条白线添加红色的属性underlineColorAndroid<TextInputplaceholder"搜索关键字"
Stella981 Stella981
4年前
Angular组件交互
Angular2中的组件交互方式很多,可分为父子组件交互和非父子组件交互两种情况。在学习之前需要了解组件的@Input(https://my.oschina.net/InPuto)和@Output(https://my.oschina.net/output1314)的用法//子组件中内容@Input()绑定的属性名
Stella981 Stella981
4年前
Angular之自定义组件添加默认样式
Angular的核心思想之一就是:组件化。组件化可以使我们的代码更好的复用。在使用官方提供的Angular库AngularMaterial时,细心的同学就会发现,Material的每一个组件都有它自己样式,如:按钮:matbutton工具条:mattoolbar表格
Wesley13 Wesley13
4年前
HTML5的表单input元素的新属性
    知识点《HTML5的表单input元素的新属性》,留待学习分享。。。<!HTML5的表单input元素的新属性Autocomplete:自动完成功能Autofocus:自动获取焦点Form:所属表单Required:必填Pattern:验证input的模式placeholder:提示\
Stella981 Stella981
4年前
Angular性能优化实践——巧用第三方组件和懒加载技术
应该有很多人都抱怨过Angular应用的性能问题。其实,在搭建Angular项目时,通过使用打包、懒加载、变化检测策略和缓存技术,再辅助第三方组件,便可有效提升项目性能。为了帮助开发者深入理解和使用Angular,本文将以我司客户中最为典型的业务场景——在线表格编辑为例,演示如何借助懒加载技术,在基于Angular的框架中实现在线导入导出Excel
Wesley13 Wesley13
4年前
JBolt开发平台入门(13)
在开发中,有些业务简单的select可以满足,在复杂点AutoSelect组件可以满足AutoSelect组件已经可以满足配置几个html属性就能完成数据自动加载、组装、显示、个性化、校验、自动选中默认值等最近JFinal开发者计划成员群里有人喊需要autocomplete组件,在input上输入个关键字,希望通过关键字去数据库里查询相关数据