我有一个Angular Component(5.2),它相对于另一个元素的nativeElement.getBoundingClientRect()
输出定位。
在测试中,我创建了一个包含样式的包装器组件来模拟定位元素,但返回的ClientRect
始终为零。
有没有办法让Angular 实际将我的元素放在DOM中?
举例说明,这是我的TestComponent
。在内部,<popup>
组件将使用anchor.nativeElement.getBoundingClientRect()
计算其固定位置。
我不认为这是相关的,但我正在使用Jest来执行测试。
我已尝试使用和而不使用 async()
。
@Component({
selector: 'test',
styles: [`
:host {
width: 1000px;
height: 1000px;
display: flex;
justify-content: center;
align-content: center;
}
`],
template: `
<button #button></button>
<popup [anchor]="button">
<div id="helloWorld">hello world</div>
</popup>
`
})
class TestComponent {
@ViewChild('button')
public buttonElement: ElementRef;
}
describe('test', () => {
let fixture;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [TestComponent],
imports: [PopupModule]
}).compileComponents().then(() => {
fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();
});
}));
it('should be positioned', () => {
const button = fixture.componentInstance.buttonElement.nativeElement;
// Either of these always fail, because the button is not positioned.
// I have also tried using fixed positioning of the button.
// this will fail
expect(button.getBoundingClientRect().top).not.toEqual(0);
// this will fail, too
return fixture.whenRenderingDone().then(() => {
expect(button.getBoundingClientRect().top).not.toEqual(0);
});
});
});
答案 0 :(得分:0)
对我来说,当我在viewChild元素上使用此方法时,一切都开始起作用,我这样声明:
@ViewChild('progress', { static: true }) progress;
之后,可以使用getBoundingClientRect
方法。
this.progress.nativeElement.getBoundingClientRect()
PS:当我使用ElementRef时,它对我没有用。仅使用ViewChild可以。
答案 1 :(得分:0)
长话短说:
您只需要在ngAfterViewInit()挂钩中使用nativeElement
类型的ElementRef
,您的测试就会“看到” DOM中的元素。
长时间阅读:
.getBoundingClientRect()
仅在元素已经渲染并存在于DOM中时才起作用。今天,当我尝试访问被单击的元素时遇到了这种情况,并且使用[routerLink]
时,它是由路由器操作动态重新渲染的-我无法从视觉上识别此行为。它会导致此元素消失,并且无法进行任何测量。接下来,呈现了一些相似的元素,但ClientRect中的值为0,0,0,0。
因此,如果您使用某些元素的动态重新渲染功能(例如菜单或其他功能),则element.getBoundingClientRect()
仅在元素消失,重新渲染或位于“”时才返回0,0,0,0。动作时间”(点击等)在DOM中尚不存在,就像您的情况一样。
因此,您需要等待,否则它将被重新渲染,然后下一步-您可以通过.getBoundingClientRect()
获得其度量值。对于@ViewChild()
最佳等待方式是ngAfterViewInit()
钩子,您可以在其中访问nativeElement(作为最佳方法)。另外-有一些技巧,例如:
private elementInited$ = new Subject();
public desiredElement: ElementRef;
@ViewChild('someElemRef') set setElementRef(el: ElementRef) {
if (!!el) {
this.desiredElement= el;
this.elementInited$.next();
}
}
ngOnInit() {
this.elementInited$.subscribe((inited) => {
// do stuff with nativeElement
const values = this.desiredElement.nativeElement.getBoundingClientRect() // <== works!
})
}
但是它太棘手了:)
另外,等待元素的好方法是@Directive()
。
使用指令,您可以以“角度方式”正确侦听元素,并且仅当元素存在于DOM中时指令才会触发。
在Devtools中使用Chrome的渲染突出显示功能也可能非常有用-只需打开devtools菜单-More tools > rendering > Paint flashing
复选框有助于识别要重新渲染的元素。