属性型指令会修改元素、组件或其他指令的行为。它的名字反映了该指令的应用方式:作为宿主元素的一个属性。
如果你要试验本指南中所讲的应用,请在浏览器中运行它或下载并在本地运行它。
本范例应用的 HighlightDirective
会根据数据绑定中的颜色或默认颜色(浅灰)来设置元素的背景色。它还会把该元素的自定义属性(customProperty
)设置为 true
,当然这除了示范本技术之外别无它用。
import { Directive, ElementRef, Input, OnChanges } from "@angular/core";
@Directive({ selector: "[highlight]" })
export class HighlightDirective implements OnChanges {
defaultColor = "rgb(211, 211, 211)"; // lightgray
@Input("highlight") bgColor = "";
constructor(private el: ElementRef) {
el.nativeElement.style.customProperty = true;
}
ngOnChanges() {
this.el.nativeElement.style.backgroundColor = this.bgColor || this.defaultColor;
}
}
它在整个应用中都用到过,也许最简单的是在 AboutComponent
中:
import { Component } from "@angular/core";
@Component({
template: `
<h2 highlight="skyblue">About</h2>
<h3>Quote of the day:</h3>
<twain-quote></twain-quote>
`
})
export class AboutComponent { }
要想在 AboutComponent
中测试 HighlightDirective
的特定用法,只需要浏览组件测试场景中的“嵌套组件测试”一节中提到的各种技巧。
beforeEach(() => {
fixture = TestBed.configureTestingModule({
declarations: [ AboutComponent, HighlightDirective ],
schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
})
.createComponent(AboutComponent);
fixture.detectChanges(); // initial binding
});
it("should have skyblue <h2>", () => {
const h2: HTMLElement = fixture.nativeElement.querySelector("h2");
const bgColor = h2.style.backgroundColor;
expect(bgColor).toBe("skyblue");
});
但是,测试单个用例不太可能涉及指令的全部能力。要找到并测试那些使用了该指令的所有组件会很乏味、很脆弱,而且几乎不可能做到完全覆盖。
纯类测试可能会有一点帮助,但像这种属性型指令往往会操纵 DOM。孤立的单元测试不会触及 DOM,因此也无法给人带来对指令功效的信心。
更好的解决方案是创建一个人工测试组件来演示应用该指令的所有方法。
@Component({
template: `
<h2 highlight="yellow">Something Yellow</h2>
<h2 highlight>The Default (Gray)</h2>
<h2>No Highlight</h2>
<input #box [highlight]="box.value" value="cyan"/>`
})
class TestComponent { }
这个
<input>
用例将 HighlightDirective
绑定到输入框中颜色值的名称。初始值是单词“cyan”,应该把它设为输入框的背景颜色。
下面是对该组件的一些测试:
beforeEach(() => {
fixture = TestBed.configureTestingModule({
declarations: [ HighlightDirective, TestComponent ]
})
.createComponent(TestComponent);
fixture.detectChanges(); // initial binding
// all elements with an attached HighlightDirective
des = fixture.debugElement.queryAll(By.directive(HighlightDirective));
// the h2 without the HighlightDirective
bareH2 = fixture.debugElement.query(By.css("h2:not([highlight])"));
});
// color tests
it("should have three highlighted elements", () => {
expect(des.length).toBe(3);
});
it("should color 1st <h2> background "yellow"", () => {
const bgColor = des[0].nativeElement.style.backgroundColor;
expect(bgColor).toBe("yellow");
});
it("should color 2nd <h2> background w/ default color", () => {
const dir = des[1].injector.get(HighlightDirective) as HighlightDirective;
const bgColor = des[1].nativeElement.style.backgroundColor;
expect(bgColor).toBe(dir.defaultColor);
});
it("should bind <input> background to value color", () => {
// easier to work with nativeElement
const input = des[2].nativeElement as HTMLInputElement;
expect(input.style.backgroundColor)
.withContext("initial backgroundColor")
.toBe("cyan");
input.value = "green";
// Dispatch a DOM event so that Angular responds to the input value change.
input.dispatchEvent(new Event("input"));
fixture.detectChanges();
expect(input.style.backgroundColor)
.withContext("changed backgroundColor")
.toBe("green");
});
it("bare <h2> should not have a customProperty", () => {
expect(bareH2.properties["customProperty"]).toBeUndefined();
});
一些技巧值得注意:
By.directive
谓词是一种获取那些不知道类型但都附有本指令的元素的好办法。By.css("h2:not([highlight])")
中的 :not伪类可以帮助你找到那些没有该指令的 <h2>
元素。By.css("*:not([highlight])")
可以找到没有该指令的任意元素。DebugElement.styles
提供了对元素样式的访问,即使没有真正的浏览器也是如此,这要归功于 DebugElement
提供的抽象。但是,如果 nativeElement
显得比使用其抽象版本更容易或更清晰,那就把它暴露出来。<h2>
上的注入器来获取它的 HighlightDirective
实例及其 defaultColor
。DebugElement.properties
允许访问本指令设置的自定义属性。导入语言环境数据的全局变体如果你使用--localize选项运行ngbuild命令,则AngularCLI会自动包含语言环境数据。ng build ...
与ServiceWorker通讯把ServiceWorkerModule导入到你的AppModule中不仅会注册ServiceWorker,还会提供一些服务,让你能和...
Angular Universal:Angular 统一平台简介本指南讲的是Angular Universal(统一平台),一项在服务端运行 Angular 应用的技术。...
部署当你准备把Angular应用部署到远程服务器上时,有很多可选的部署方式。最简单的部署选项在完整部署应用之前,你可以先临时用...