面试题答案
一键面试1. Angular中ngIf指令底层实现逻辑
- 视图创建:
- 在Angular的模板解析阶段,
ngIf
指令会被解析。当ngIf
绑定的表达式值为true
时,ngIf
会触发视图的创建。 - 从源码角度看,
ngIf
指令对应的类是NgIf
,它继承自NgIfContext
。NgIf
指令内部维护了一个ViewContainerRef
,这是视图容器的引用,用于创建和管理视图。 - 当表达式值为
true
时,NgIf
通过ViewContainerRef
的createEmbeddedView
方法来创建嵌入视图。这个方法会从模板中生成新的视图,并将其插入到DOM中。
- 在Angular的模板解析阶段,
- 视图销毁:
- 当
ngIf
绑定的表达式值变为false
时,ngIf
会销毁当前的视图。 NgIf
指令会调用ViewContainerRef
的clear
方法,该方法会移除当前视图容器中的所有视图,从而实现视图的销毁。同时,相关的变更检测机制会停止对这些视图的检测,释放资源。
- 当
- 视图更新:
NgIf
指令通过变更检测机制来监听绑定表达式的值的变化。当表达式的值发生变化时,Angular的变更检测机制会触发。- 如果表达式从
false
变为true
,则重新创建视图;如果从true
变为false
,则销毁视图。NgIf
指令依赖于Angular的默认变更检测策略(默认是DefaultChangeDetectionStrategy
),该策略会在每个组件的变更检测周期内检查表达式的值。
2. 为ngIf指令扩展在视图销毁时执行自定义动画的实现
- 步骤一:创建动画服务
- 首先,创建一个动画服务,用于定义和执行动画逻辑。例如:
import { Injectable } from '@angular/core';
import { AnimationBuilder, AnimationPlayer } from '@angular/animations';
@Injectable({
providedIn: 'root'
})
export class CustomAnimationService {
constructor(private animationBuilder: AnimationBuilder) {}
playDestroyAnimation(element: HTMLElement): AnimationPlayer {
const animation = this.animationBuilder.build([
// 定义动画逻辑,例如淡入淡出
style({ opacity: 1 }),
animate('500ms ease-out', style({ opacity: 0 }))
]);
const player = animation.create(element);
player.play();
return player;
}
}
- 步骤二:扩展NgIf指令
- 创建一个自定义指令,继承自
NgIf
指令,并在视图销毁时调用动画服务。
- 创建一个自定义指令,继承自
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
import { NgIf, NgIfContext } from '@angular/common';
import { CustomAnimationService } from './custom - animation.service';
@Directive({
selector: '[appExtendedNgIf]',
providers: [
{
provide: NgIf,
useExisting: ExtendedNgIf
}
]
})
export class ExtendedNgIf extends NgIf {
constructor(
templateRef: TemplateRef<NgIfContext>,
viewContainer: ViewContainerRef,
private customAnimationService: CustomAnimationService
) {
super(templateRef, viewContainer);
}
override set ngIf(condition: boolean) {
if (!condition && this._viewRef) {
const element = this._viewRef.rootNodes[0] as HTMLElement;
const player = this.customAnimationService.playDestroyAnimation(element);
player.onDone(() => {
super.ngIf = condition;
});
} else {
super.ngIf = condition;
}
}
}
- 步骤三:在模板中使用
- 在模板中使用自定义的
appExtendedNgIf
指令代替原生的ngIf
指令。
- 在模板中使用自定义的
<div *appExtendedNgIf="showDiv">
<p>This is a div that can be toggled with custom destroy animation.</p>
</div>
<button (click)="showDiv =!showDiv">Toggle Div</button>
在上述代码中,当appExtendedNgIf
绑定的条件变为false
时,会先执行自定义的销毁动画,动画完成后再真正销毁视图。