在angular中如何深度watch一个对象?

1,130 阅读1分钟

突然想到,vue可以deep watch一个对象,并提供回调

angular怎么搞呢?答:ngDoCheck加一个if,然后深度判断那个对象即可,就是深度判断方法要自己写或者引入什么其他工具库吧

然后搜到了一个很牛的service例子,深度对比服务,主要这个服务还能内部缓存旧值,不需要你自己去找

import { KeyValueChanges, KeyValueDiffer, KeyValueDiffers } from '@angular/core';

export class Customer {
  firstName: string;
  favoriteColor: string;
}

@Component({
  selector: 'my-app',
  templateUrl: `./app.component.html`
})
export class AppComponent {
  private customerDiffer: KeyValueDiffer<string, any>;
  private customer: Customer;

  constructor(private differs: KeyValueDiffers) {}

  ngOnInit(): void {
    this.customer = new Customer();
    this.customerDiffer = this.differs.find(this.customer).create();
  }

  customerChanged(changes: KeyValueChanges<string, any>) {
    console.log('changes');
    /* If you want to see details then use
      changes.forEachRemovedItem((record) => ...);
      changes.forEachAddedItem((record) => ...);
      changes.forEachChangedItem((record) => ...);
    */
  }

  ngDoCheck(): void {
      const changes = this.customerDiffer.diff(this.customer);
      if (changes) {
        this.customerChanged(changes);
      }
  }
}

stackoverflow.com/questions/4…

但是,ngDoCheck 会被高频调用,虽说通常性能没问题,但如果用不好,还是可能出现性能问题的。考虑回rxjs,还是更接近这种主动推送的做法,应当是更好的,如果要进一步做深度监听的话,就配合上面发现的differ服务吧,这是我实现的小例子,用setter监听,用subject推送

/**
 * 监听指定的属性 返回可订阅的 watcher 类似 vue
 * 通过 takeUntil 自动取消订阅
 * @param dataParent 对象引用
 * @param key 属性名
 * @param destory$ 组件实例销毁信号
 * @returns 
 */
export function watchData$$(dataParent: unknown, key: string, destory$: Subject<void>) {
  const watcher$ = new Subject<{newVal, oldVal}>();
  let value = dataParent[key]; // 用闭包将值私藏起来 同时暴露get方法也能参与变更检测 
  Object.defineProperty(dataParent, key, {
    get() { return value },
    set(newVal) {
      const oldVal = value;
      value = newVal;
      watcher$.next({newVal, oldVal});
    }
  });
  return watcher$.pipe(takeUntil(destory$));
}