MST
星途 面试题库

面试题:自定义Angular数据绑定指令及优化其性能

请你基于Angular的底层数据绑定原理,实现一个自定义的双向数据绑定指令。要求这个指令不仅能正确实现数据的双向同步,还要考虑到性能优化,比如如何避免不必要的变化检测循环,以及如何在复杂应用场景下确保指令的高效运行。请详细阐述实现思路及关键代码点。
45.2万 热度难度
前端开发Angular

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 指令定义:使用Angular的@Directive装饰器定义一个新的指令。
  2. 属性绑定:利用@Input()装饰器绑定输入属性,用于从组件传递数据到视图。
  3. 事件绑定:使用@Output()装饰器绑定输出属性,用于从视图传递数据变化通知到组件。
  4. 变化检测:合理利用Angular的变化检测机制,避免不必要的循环。例如,使用ChangeDetectorRef来手动触发变化检测,并且通过NgZone控制检测的执行范围。
  5. 性能优化:在复杂场景下,通过减少不必要的DOM操作和变化检测频率来提升性能。例如,使用防抖(Debounce)或节流(Throttle)技术处理频繁触发的事件。

关键代码点

  1. 指令定义与输入输出绑定
import { Directive, Input, Output, EventEmitter } from '@angular/core';

@Directive({
  selector: '[myTwoWayBinding]'
})
export class MyTwoWayBindingDirective {
  @Input('myTwoWayBinding') value: any;
  @Output('myTwoWayBindingChange') valueChange = new EventEmitter<any>();

  constructor() {}
}
  1. 在模板中使用指令
<input type="text" [myTwoWayBinding]="data" (myTwoWayBindingChange)="data = $event">
  1. 处理视图变化并通知组件
import { Directive, Input, Output, EventEmitter, ElementRef, HostListener } from '@angular/core';

@Directive({
  selector: '[myTwoWayBinding]'
})
export class MyTwoWayBindingDirective {
  @Input('myTwoWayBinding') value: any;
  @Output('myTwoWayBindingChange') valueChange = new EventEmitter<any>();

  constructor(private el: ElementRef) {}

  @HostListener('input', ['$event.target.value'])
  onInputChange(newValue: string) {
    if (this.value!== newValue) {
      this.value = newValue;
      this.valueChange.emit(newValue);
    }
  }
}
  1. 手动触发变化检测(可选)
import { Directive, Input, Output, EventEmitter, ElementRef, HostListener, ChangeDetectorRef } from '@angular/core';

@Directive({
  selector: '[myTwoWayBinding]'
})
export class MyTwoWayBindingDirective {
  @Input('myTwoWayBinding') value: any;
  @Output('myTwoWayBindingChange') valueChange = new EventEmitter<any>();

  constructor(private el: ElementRef, private cdRef: ChangeDetectorRef) {}

  @HostListener('input', ['$event.target.value'])
  onInputChange(newValue: string) {
    if (this.value!== newValue) {
      this.value = newValue;
      this.valueChange.emit(newValue);
      this.cdRef.markForCheck(); // 手动标记变化检测
    }
  }
}
  1. 利用NgZone控制变化检测范围(可选)
import { Directive, Input, Output, EventEmitter, ElementRef, HostListener, ChangeDetectorRef, NgZone } from '@angular/core';

@Directive({
  selector: '[myTwoWayBinding]'
})
export class MyTwoWayBindingDirective {
  @Input('myTwoWayBinding') value: any;
  @Output('myTwoWayBindingChange') valueChange = new EventEmitter<any>();

  constructor(private el: ElementRef, private cdRef: ChangeDetectorRef, private ngZone: NgZone) {}

  @HostListener('input', ['$event.target.value'])
  onInputChange(newValue: string) {
    this.ngZone.run(() => {
      if (this.value!== newValue) {
        this.value = newValue;
        this.valueChange.emit(newValue);
        this.cdRef.markForCheck();
      }
    });
  }
}