MST
星途 面试题库

面试题:Angular自定义指令与依赖注入及变更检测机制的深度整合

在Angular应用中,有一个复杂业务场景需要自定义指令与依赖注入及变更检测机制深度整合。自定义指令需要依赖一个服务,且要在指令的生命周期钩子中,根据依赖服务的数据变化,触发精准的变更检测,从而优化性能。请详细说明实现方案,包括自定义指令的结构、依赖服务的设计以及变更检测的策略与代码实现。
29.9万 热度难度
前端开发Angular

知识考点

AI 面试

面试题答案

一键面试

1. 自定义指令结构

  1. 创建指令:使用 ng generate directive 命令生成自定义指令,例如 ng generate directive myCustomDirective
  2. 导入依赖:在指令文件(my - custom - directive.ts)中,导入必要的模块和类型。
import { Directive, ElementRef, HostListener, Inject, OnInit, OnDestroy, Input, ChangeDetectorRef } from '@angular/core';
import { MyService } from './my - service';
  1. 指令类定义
@Directive({
  selector: '[appMyCustomDirective]'
})
export class MyCustomDirective implements OnInit, OnDestroy {
  @Input() someInput: string;
  private subscription: any;

  constructor(
    private el: ElementRef,
    private cdRef: ChangeDetectorRef,
    @Inject(MyService) private myService: MyService
  ) {}
  1. 生命周期钩子
    • ngOnInit:在指令初始化时,订阅依赖服务的数据变化。
ngOnInit() {
  this.subscription = this.myService.data$.subscribe(data => {
    // 根据服务数据变化执行操作
    this.doSomethingWithData(data);
    // 触发变更检测
    this.cdRef.markForCheck();
  });
}
- `ngOnDestroy`:在指令销毁时,取消订阅,防止内存泄漏。
ngOnDestroy() {
  this.subscription.unsubscribe();
}
  1. 自定义方法
private doSomethingWithData(data: any) {
  // 例如修改指令所在元素的文本内容
  this.el.nativeElement.textContent = `Data from service: ${data}`;
}

2. 依赖服务设计

  1. 创建服务:使用 ng generate service 命令生成服务,例如 ng generate service my - service
  2. 导入依赖:在服务文件(my - service.ts)中,导入 Injectable 装饰器和 Observable 相关模块。
import { Injectable } from '@angular/core';
import { Observable, BehaviorSubject } from 'rxjs';
  1. 服务类定义
@Injectable({
  providedIn: 'root'
})
export class MyService {
  private dataSubject = new BehaviorSubject<any>(null);
  public data$ = this.dataSubject.asObservable();

  updateData(newData: any) {
    this.dataSubject.next(newData);
  }
}

3. 变更检测策略与代码实现

  1. 变更检测策略选择:使用 markForCheck 方法进行精准的变更检测。在指令中,当依赖服务的数据发生变化时,调用 cdRef.markForCheck() 方法通知 Angular 检查该指令及其子组件的变化。
  2. 优化策略
    • 局部检测:通过 markForCheck 只触发指令及其子组件的检测,而不是整个应用的检测,从而提升性能。
    • 避免不必要检测:在 doSomethingWithData 方法中,可以添加逻辑判断,只有当数据真正发生变化时才调用 markForCheck,进一步减少不必要的检测。例如:
private lastData: any;
private doSomethingWithData(data: any) {
  if (data!== this.lastData) {
    // 例如修改指令所在元素的文本内容
    this.el.nativeElement.textContent = `Data from service: ${data}`;
    this.lastData = data;
    // 触发变更检测
    this.cdRef.markForCheck();
  }
}