Javascript 如何使用Angular 2正确检测计算样式属性中的更改?
我已经创建了一个Angular 2应用程序,其中包含一个组件,我正试图相对于另一个组件定位该组件的HTML元素。为了计算精确的坐标,我需要知道浏览器渲染的元素的宽度和高度 我正在使用Javascript 如何使用Angular 2正确检测计算样式属性中的更改?,javascript,css,angular,dom,getcomputedstyle,Javascript,Css,Angular,Dom,Getcomputedstyle,我已经创建了一个Angular 2应用程序,其中包含一个组件,我正试图相对于另一个组件定位该组件的HTML元素。为了计算精确的坐标,我需要知道浏览器渲染的元素的宽度和高度 我正在使用window.getComputedStyle(this.elementRef.nativeElement)获取这些属性。我注意到,在呈现页面时,属性会不断更改,直到页面呈现完成。为了了解任何更改并调整定位,我检查了组件的ngafterview checked方法中的值 但是,当渲染导致新的计算样式属性时,似乎不会调
window.getComputedStyle(this.elementRef.nativeElement)
获取这些属性。我注意到,在呈现页面时,属性会不断更改,直到页面呈现完成。为了了解任何更改并调整定位,我检查了组件的ngafterview checked
方法中的值
但是,当渲染导致新的计算样式属性时,似乎不会调用ngAfterViewChecked
,因为我发现我的钩子不再被调用,即使计算样式属性仍在更改。我假设角度框架的设计不是为了检测这种变化
我的第一次尝试是实现ngDoCheck
hook,但是似乎在一段时间之后,在computed style属性具有其最终值之前,也没有调用这个钩子。我假设我还没有完全理解何时要调用这个钩子
我最终发现,如果我在ngafterview checked
中实现setTimeout
函数,这将导致以后再次调用同一个钩子,即使我只传递一个伪函数,如:
setTimeout(() => {}, 500);
但坦率地说,我不明白为什么会这样有人能给我解释一下setTimeout
和ngafterview checked
hook之间的连接吗?
虽然这似乎是一项有点棘手的工作:检测和处理计算样式属性变化的正确“角度”方法是什么?
代码摘录:
export class MyComponent implements OnInit, AfterViewChecked
{
private cssWidth: number;
private cssHeight: number;
constructor(private elementRef: ElementRef, private renderer: Renderer2)
{
}
ngAfterViewChecked()
{
console.log("ngAfterViewChecked");
this.updateView();
}
public updateView()
{
const sizeX = parseFloat(window.getComputedStyle(this.elementRef.nativeElement).width) || 0;
const sizeY = parseFloat(window.getComputedStyle(this.elementRef.nativeElement.height) || 0;
if (sizeX === this.cssWidth && sizeY === this.cssHeight) {
// no change
return;
}
console.log("Change detected!");
// TODO Does not work without this dummy timeout function (else no more changes detected) - why so??
setTimeout(() => {}, 500);
[.. doing the positioning here ..]
}
在香草JavaScript中,您可以使用: 并在DOM更改时触发您自己的函数 MutationObserver为开发人员提供了一种方法来对 大教堂。它被设计成一个替代品,用于替换在中定义的突变事件 DOM3事件规范 请参见上图以查看生命周期图。如果doCheck中的钩子不起作用,AfterViewChecked也不会起作用,因为doCheck启动AfterViewChecked 每次异步进程完成时,都会发生另一轮doCheck。这将调用AfterViewChecked,并调用updateView函数。SetTimout()是一个异步进程。我怀疑上面的代码会无限循环 我相信您想要的是让这里显示的父组件使用ngAfterViewChecked()并调用updateView()。我们将探讨这一主题 使两个组件协同工作的方法是让父组件可以在子组件之间传递更改,因为父组件是可以查看子组件中发生的事件的上下文
我个人使用的解决方案是一个EventEmitter,在未显示的组件中,在ngOnInit()函数中。它将通知父级它已初始化。然后,在父组件中,在发出的事件上进行函数调用,该事件告诉子组件您要在此处更新查看。为什么在渲染导致新的计算样式属性时不调用ngAfterViewChecked? Angular框架不会检测DOM元素的计算样式中的更改,至少在浏览器的渲染引擎导致更改时不会检测到。因此,在这种情况下不会调用
ngAfterViewChecked
钩子
为什么使用setTimeout时它会工作?
正如Michael Palmer在回答中所解释的那样,setTimeout
会使Angular意识到一个可能导致更改的异步进程。因此,在执行超时功能后,将调用ngAfterViewChecked
钩子。Angular不会尝试检查在setTimeout
函数中到底做了什么,以及这是否会影响视图。显然,这将很难实现,可能不值得付出努力。相反,Angular调用ngAfterViewChecked
hook,以防异步进程中发生影响视图的事情
聆听计算风格变化的角度方式是什么?
除了使用
setTimeout
来查看DOM元素计算样式的更改之外,似乎没有其他方法了。对不起,我知道这并不能完全解决您的问题,但我希望它至少部分有用:)无论如何,谢谢,但我已经尝试了observe(this.elementRef.nativeElement,{attributes:true})
这给了我多个回调,oldValue=null,newValue=undefined,仅此而已。我实际上怀疑是否会检测到DOM更改。我假设DOM不会改变,但只有getComputedStyle函数会计算不同的结果?!虽然这是一个有趣的选择,但经过一些研究,我得出结论,MutationObserver目前不支持观察计算样式属性。另请参见问题“是”,它不侦听计算的样式更改,作为CSS OM的一部分。什么是获得计算样式更改的解决方案?谢谢,我现在知道,任何异步进程都会导致调用ngDoCheck
和ngAfterViewChecked
,其中setTimeout
是一种可能性,而不管调用什么函数setTimeout
(即使在我的情况下没有)。顺便说一句,这不是一个无限循环,因为我不再在检测不到更改时发出setTimeout
。然而,你剩下的答案似乎是基于误解