在Angular 2中,DOM操作应该放在哪里?
在Angular 2中,DOM操作应该放在哪里?
在Angular 1中,所有的DOM操作都应该在指令中完成,以确保正确的可测试性,但是在Angular 2中有什么变化呢?
我一直在寻找关于在哪里放置DOM操作以及如何进行思考的好文章或任何信息,但每次都找不到。
以这个组件为例(这实际上是一个指令,但我们假装它不是):
export class MyComponent { constructor(private _elementRef: ElementRef) { this.setHeight(); window.addEventListener('resize', (e) => { this.setHeight(); }); } setHeight() { this._elementRef.nativeElement.style.height = this.getHeight() + 'px'; } getHeight() { return window.innerHeight; } }
例如,事件绑定应该放在构造函数中,还是应该放在ngAfterViewInit
函数或其他地方?你应该尝试将组件的DOM操作拆分成指令吗?
目前一切都很模糊,所以我不确定自己是否做得正确,我相信我不是唯一一个有这种困惑的人。
在Angular2中,DOM操作有哪些规则?
Angular 2中应该尽量避免直接操作DOM。相反,应该使用绑定来实现,如下所示:
export class MyComponent { constructor() { this.setHeight(); } ('style.height.px') height:number; ('window:resize', ['$event']) setHeight() { this.height = window.innerHeight; } }
你能详细解释一下吗?
(...)
注册了一个事件监听器,(...)
更新了height
样式的值为number
的值。事件处理程序是错误的。我更新了我的答案(抱歉,在写这个答案的时候我只有手机)。
直接操作DOM与服务器端渲染和使用Angular的WebWorkers支持不兼容。
嗯,好吧,我有点理解了,但是我不太理解这一部分 ('style.height.px') height:number;
,height:number
是做什么的?
这似乎表明监听器将监听宿主元素的调整大小,而不是窗口?
抱歉,我忽略了window
。我更新了我的答案。
在阅读Dart文档时,我找到了答案,哈哈。不管怎样,谢谢 🙂 现在我需要大量重写代码了...唉。
这可能是正确的,在许多情况下,包括上面的情况,在模板中使用绑定已经足够。然而,有很多情况下,直接操作DOM是必要的,而模板是不够的。Angular 1通过link函数给了我们一个逃生通道。
我知道有些情况下这很困难或者不可能,但这是你应该努力的方向。我对Angular1了解不多。在Angular2中,你也可以操作DOM,但如果你想使用WebWorkers或服务器端渲染,这有它的缺点。你还可以使用ViewContainerRef.createComponent()
在运行时动态添加/删除组件,甚至在运行时创建组件。
DOM操作在Angular 2中的位置是一个经常被讨论的问题。在开发者推荐的解决方案中,他们建议将DOM操作放在AfterViewInit生命周期钩子中进行。这样可以确保组件的视图已经初始化完成,可以安全地进行DOM操作。
以下是一个示例代码:
({ selector: 'my-comp', template: `` }) export class MyComp implements AfterViewInit { @ViewChild('myContainer') container: ElementRef; constructor() {} ngAfterViewInit() { var container = this.container.nativeElement; console.log(container.width); // or whatever } })
需要注意的是,视图子组件的名称必须以"my"开头,并且在模板中需要使用"#myContainer"来引用。同时,还需要添加适当的导入语句:
import { AfterViewInit, ViewChild, ElementRef } from '/core';
在讨论中,有人问到名称中是否必须包含前缀"my",或者是指在代码中引用的名称必须与模板中的"#whatever"对应。回答是名称中不必包含"my"前缀,只需要保持一致即可。不过,强烈建议在名称中使用个人/自定义前缀,以避免与其他模块冲突。
虽然这个问题可能对你来说已经不再重要,但对其他人来说可能仍然有参考价值。