面试题答案
一键面试可能遇到的冲突
- 执行顺序不明确:自定义指令与内置指令(如
NgIf
、NgClass
)同时作用于一个DOM元素时,执行顺序不确定,可能导致预期外的结果。例如,NgIf
决定元素是否显示,若自定义指令在NgIf
之前执行,且自定义指令依赖元素在DOM中存在,就会出错。 - 对同一属性的操作冲突:如果自定义指令和内置指令都尝试操作同一个DOM属性,可能导致属性值的覆盖或异常。比如自定义指令和
NgClass
都尝试设置元素的class
属性。
处理冲突确定执行优先级
- 使用
@Directive
装饰器的priority
属性:在自定义指令中,通过@Directive
装饰器的priority
属性来设置指令的优先级。数值越大,优先级越高。Angular内置指令的优先级有默认值,例如NgIf
的优先级较高。通过设置自定义指令的priority
高于或低于内置指令,可以控制执行顺序。 - 合理设计指令逻辑:确保自定义指令的逻辑不依赖于内置指令可能改变的DOM状态(如元素是否存在)。例如,在自定义指令中添加检查,判断元素是否存在再进行操作。
代码示例
- 创建自定义指令
import { Directive, ElementRef, Input, OnChanges, SimpleChanges, Renderer2, priority } from '@angular/core'; @Directive({ selector: '[appHighlight]', priority: 1000 // 设置较高优先级 }) export class HighlightDirective implements OnChanges { @Input('appHighlight') color: string; constructor(private el: ElementRef, private renderer: Renderer2) {} ngOnChanges(changes: SimpleChanges): void { if (changes.color) { this.renderer.setStyle(this.el.nativeElement, 'background-color', this.color); } } }
- 在模板中使用
<div *ngIf="showDiv" [ngClass]="{ 'active': isActive }" [appHighlight]="highlightColor"> This is a div. </div>
import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { showDiv = true; isActive = true; highlightColor = 'yellow'; }
测试方案
- 单元测试自定义指令
- 使用
TestBed
配置测试模块,将自定义指令包含进去。 - 创建一个模拟的DOM元素,并将自定义指令应用到该元素上。
- 通过改变
@Input
属性的值,检查DOM元素的样式是否按照预期改变。
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { HighlightDirective } from './highlight.directive'; import { Component } from '@angular/core'; @Component({ template: `<div [appHighlight]="color"></div>` }) class TestComponent { color = 'yellow'; } describe('HighlightDirective', () => { let fixture: ComponentFixture<TestComponent>; beforeEach(() => { TestBed.configureTestingModule({ declarations: [HighlightDirective, TestComponent] }); fixture = TestBed.createComponent(TestComponent); fixture.detectChanges(); }); it('should set background color', () => { const divElement = fixture.nativeElement.querySelector('div'); expect(window.getComputedStyle(divElement).backgroundColor).toBe('rgb(255, 255, 0)'); }); });
- 使用
- 集成测试指令组合
- 创建一个组件,在模板中同时应用自定义指令和内置指令。
- 通过改变组件的属性值,检查DOM元素的显示、样式等是否符合预期。
- 例如,改变
*ngIf
的条件,检查自定义指令在元素显示/隐藏时的行为。
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { HighlightDirective } from './highlight.directive'; import { Component } from '@angular/core'; @Component({ template: `<div *ngIf="showDiv" [ngClass]="{ 'active': isActive }" [appHighlight]="highlightColor">Test</div>` }) class IntegrationTestComponent { showDiv = true; isActive = true; highlightColor = 'yellow'; } describe('Integration of Directives', () => { let fixture: ComponentFixture<IntegrationTestComponent>; beforeEach(() => { TestBed.configureTestingModule({ declarations: [HighlightDirective, IntegrationTestComponent] }); fixture = TestBed.createComponent(IntegrationTestComponent); fixture.detectChanges(); }); it('should show div with correct style when conditions are met', () => { const divElement = fixture.nativeElement.querySelector('div'); expect(divElement).toBeTruthy(); expect(window.getComputedStyle(divElement).backgroundColor).toBe('rgb(255, 255, 0)'); }); it('should hide div when *ngIf condition is false', () => { fixture.componentInstance.showDiv = false; fixture.detectChanges(); const divElement = fixture.nativeElement.querySelector('div'); expect(divElement).toBeFalsy(); }); });