监听被 ng-content 替换的元素的 className 变化

Listen to className changes on an element replaced by ng-content

我需要监听被 <ng-content> 替换的元素的 class 名称更改。我尝试了很多方法,我找到的唯一方法是使用 setInterval,我认为这不是一个好习惯。假设我将在 <app-child> 组件

中注入一个 input 元素
@Component({
  selector: 'app-parent',
  template: `
    <app-child>
     <input type="text">
    </app-child>
  `
})
export class ParentComponent implements OnInit {
  ngOnInit() { }
}

每当 inputclass 属性更改时,我想在 child.component.ts 中做一些事情:

@Component({
  selector: 'app-child',
  template: `<ng-content select="input"></ng-content>`
})
export class ChildComponent implements OnInit {
  @ContentChild(HTMLInputElement) input: any;

  ngOnInit() {
    setInterval(() => {
       const { className } = this.input.nativeElement;
       console.log(className);
    }, 500);
  }
}

这种方法设法检测到 class 变化,但 setInterval 的问题是回调将 运行 在后台每隔 500 毫秒,是否还有另一个检测变化的方法?

注意:我已经尝试过挂钩 ngAfterContentChecked,它在检测到任何更改后自动 运行,但在内部我无法访问 this.input.nativeElement.className 上的最新更改,因为如果此函数在值更改之前执行。

您可以使用 MutationObserver Api

像这样:

  ngAfterContentInit(): void {
    this.changes = new MutationObserver((mutations: MutationRecord[]) => {
      mutations.forEach((mutation: MutationRecord) => {
        // this is called twice because the old class is removed and the new added
        console.log(
          `${mutation.attributeName} changed to ${this.input.nativeElement.classList}`
        );
      });
    });

    this.changes.observe(this.input.nativeElement, {
      attributeFilter: ['class'],
    });
  }

这是一个 stackblitz 运行 https://stackblitz.com/edit/angular-ivy-tz5q88?file=src%2Fapp%2Fchild.component.ts