如何在Angular中正确地操作DOM ? 深藏阁楼爱情的钟 2022-09-12 14:56 151阅读 0赞 # 序 # 通常,当我们在Angular中使用JavaScript技术时,我们几乎会忘记框架的特性。让我们去使用它们。 web开发中一个有趣的主题是DOM操作。在Angular中,有很多方法可以操作DOM。 让我们使用它们而不是直接的JavaScript方法。 通常来说,在dom操作时会有两种概念: 1. 调整DOM元素 2. 调整DOM结构 # 调整DOM元素 # 我们熟悉很多修改DOM元素的JavaScript方法。例如: * classList.add() * setAttribute() * Style.setPropperty() 这是js中原生的一些DOM方法 在Angular中,有多种方法可以修改DOM元素。我们将讨论几乎每一种方法,并从中选择最好的。 ## 方法 ## ### 方法1 ### **概念:** 1. 模板引用变量 2. ElementRef 3. @Viewchild/@Viewchildren 4. AfterViewInit **定义:** 1. 模板引用:对特定DOM元素的引用。 2. ElementRef: ElementRef是一个类,它包含所有本地的DOM元素 3. @viewchild/@viewchildren: 从DOM中选择子元素或所有子元素 4. AfterViewInit: 这是一个生命周期钩子,在Angular组件初始化它的视图之后被调用。 @Component({ selector: 'app-root', template:`<span #el>I am manoj.</span> <span>I am a web developer.</span>`, styles:[`[highlight]{background: green; color: white}`] }) export class AppComponent implements AfterViewInit{ @ViewChild('el') span:ElementRef; ngAfterViewInit(){ this.span.nativeElement.setAttribute('highlight', ''); } } **步骤:** Step1:在这个例子中,我使用模板引用和@viewchild查询来获取一个HTML元素。 <span #el>I am manoj.</span> <span>I am a web developer.</span> @ViewChild(‘el’) span: ElementRef; Step2: DOM元素的setAttribute用于添加属性。 this.span.nativeElement.setAttribute(‘highlight’, ‘’); 页面上展示没有任何问题,它运行得很好。但是这种方法有一个问题。这里,我们混合了呈现和表示逻辑。 通常,组件(components)代表逻辑,例如定义数组、对象和迭代等等。呈现逻辑实际上是修改DOM元素。我们应该在一个单独的指令中维护渲染逻辑。我们可以通过数据绑定机制来进行组件和指令的通信。 现在让我们考虑另一种解决这个问题的方法。 ### 方法2 ### 让我们创建一个指令,并将所有的呈现逻辑放在该指令中。 **概念:** * ElementRef * @Input() * ngOnInit() **定义:** * ElementRef:它帮助去访问DOM元素 * @Input() : 数据绑定来通信组件和指令。 * ngOnInit() : 初始生命周期钩子,它在Angular创建组件后被调用。 例如: **指令:** @Directive({ selector: '[appHighlight]' }) export class HighlightDirective implements OnInit{ @Input() appHighlight; constructor( private element: ElementRef) { } ngOnInit(){ this.element.nativeElement.setAttribute(this.appHighlight, ''); } } **组件:** @Component({ selector: 'app-root', template:`<span [appHighlight]="'highlight'">I am manoj.<span> <span>I am a web developer.</span>`, styles:[`[highlight]{background: green; color: white;}`] }) export class AppComponent{ } **步骤:** \*\*Step1:\*\*将ElementRef注入到指令文件的构造函数中。 constructor( private element: ElementRef) { } **Step2:** 添加@input装饰器到指令中 @Input() appHighlight; **Step3:** 使用setAttribute()原生元素方法在ngOnInit()生命周期钩子中添加一个属性。 ngOnInit(){ this.element.nativeElement.setAttribute(this.appHighlight, ‘’)} **Step4:** 将指令应用到组件模板中的span元素: <span [appHighlight]=”’highlight’”>I am manoj.</span> 输出和前面一样,但是这里渲染逻辑从组件移动到指令。它有助于在任何地方重用相应的组件和指令。 但在这里,我们使用ElementRef类直接访问DOM元素。允许直接访问DOM会使我们的应用程序更容易受到XSS攻击。大多数人在所有地方都使用ElementRef。现在的问题是,我们应该使用什么来安全地访问DOM元素?对,我们有个解决办法。让我们看看另一种方法。 ### 方法3 ### 概念: 1渲染器(Renderer)-使直接DOM访问安全,并且它是一个独立的平台。它修改DOM元素而不直接接触DOM。呈现程序是由一些方法组成的服务。它有助于操作DOM。 下面我列出了一些渲染器方法 1.addClass() 2.removeClass() 3.setStyle() 4.removeStyle() 5.setProperty() 例子: constructor( private element: ElementRef, private renderer: Renderer2) { } ngOnInit(){ this.renderer.setAttribute(this.element.nativeElement,this.appHighlight, '') } 步骤: Step1:将渲染器注入到指令文件的构造函数中。 constructor( private renderer: Renderer2) { } Step2: 使用renderer setAttribute()方法在ngOnInit()生命周期钩子中添加一个属性。 ngOnInit(){ this.renderer.setAttribute(this.element.nativeElement , this.appHighlight, ‘’)} 这里的输出是一样的。但是我们正确且更安全地修改了DOM。像ngClass、ngStyle这样的属性指令会基于渲染器修改DOM元素。因此,接下来,我们将使用Renderer来修改DOM。这也是一种更恰当的方式。 # 调整DOM结构 # 1creatElement() 2remove() 3appendChild() 4removeChild() 下面是一些修改DOM结构的JavaScript方法的例子。这些方法我们已经很熟悉了。现在我们来看看如何在Angular中修改DOM结构。 ## 从DOM中移除一个子组件 ## ## 方法1 ## **概念:** 1Template Reference 2ElementRef 3@ViewChildren() 4AfterViewChecked 5Renderer 6QueryList **定义:** 1. Template Reference: 特定DOM元素的引用。 2. ElementRef: 帮助去访问DOM元素。 3. @ViewChildren(): 以QueryList的形式从视图dom返回指定的元素或指令 4. AfterViewChecked: 它在默认更改检测程序完成一个更改检查周期后调用。 5. Renderer: 使直接DOM访问更安全 6. QueryList: 返回类型。它只是一个项目列表。Angular在添加或删除列表项时更新QueryList。它只在ngAfterViewInit()生命周期钩子之前初始化。 Copy @Component({ selector: 'app-parent', template: `<p>parent works!</p> <app-child #child></app-child> <button (click)='removeChild()'>remove child</button>`, styleUrls: ['./parent.component.css'] }) export class ParentComponent implements AfterViewChecked{ @ViewChildren('child', { read: ElementRef}) childComp:QueryList<ElementRef> constructor(private renderer: Renderer2, private host: ElementRef) { } ngAfterViewChecked() { console.log(this.childComp.length) } removeChild(){ this.renderer.removeChild(this.host.nativeElement, this.childComp.first.nativeElement); } } **步骤:** 1. 使用template reference和ViewChildren()来获取HTML元素。 2. 将Renderer和ElementRef注入构造函数 3. 使用removecchild()方法来删除子组件 4. 为了获得宿主元素,我们需要使用ElementRef。 **显示:** \[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MSdUB27A-1632643270004)(/Users/jiangyumin/Documents/img/domoutput1.png)\] 点击移除按钮后: \[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qk0Bnqkb-1632643270006)(/Users/jiangyumin/Documents/img/click.png)\] 由此可见,我们成功地删除了子组件。但是,我想再次向您展示带有控制台日志的输出屏幕。 \[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YhcAbQEt-1632643270009)(/Users/jiangyumin/Documents/img/childcount.png)\] **问题:** 我们已经删除了子组件,但子组件计数仍然是1。为什么?如何解决? 是的,显然我们会想到这个问题。别担心,我们有办法。 ## DOM和View的关系 ## \[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ATEDYnpE-1632643270010)(/Users/jiangyumin/Documents/img/daigram.png)\] Angular有一个视图概念。看看图表;它将清楚地说明视图和DOM的关系。视图只是DOM的引用。当我们运行Angular应用时,它会创建多个视图。 对于每个组件的创建,视图也是由Angular创建的。我们看到了外部的组件层次结构。但引擎盖下的视图层次结构也是基于组件层次结构创建的。 如果我们在DOM中做了任何改变,比如拖动、添加或删除DOM元素,视图应该立即更新。否则,这将是一个问题。 **变更检测基于视图的层次结构运行。** 使用方法1,我们从DOM中删除了子组件。但是视图层次结构保持不变,并且视图没有更新。所以它展示了一个child。在这里,这是一个小场景,没有问题,但如果我们删除了10个组件,而视图没有更新,Angular仍然会对所有被删除的组件运行变更检测。这将严重影响我们的应用程序。 View Container (viewContainerRef): 视图容器使DOM结构更改安全。 ## 方法: ## 1. insert() 2. Move() 3. Remove() 4. createEmbeddedView() ### 初始化视图容器: ### 我们可以将任何DOM元素作为视图容器。但通常情况下,所有人都将作为视图容器。ng-container只是一个HTML标签,但它是Angular特有的。 视图有两种类型: 1. Embedded Views-始终是视图容器的一部分。 2. Host Views-始终是视图容器的一部分,但也是独立的。 让我们看看如何使DOM元素成为视图。 **步骤:** 1. 在模板文件中添加ng-container标签。 <ng-container #viewcontainer></ng-container> 2. 添加@viewchild以选择元素。 @ViewChild(‘viewcontainer’, { ‘read’: ViewContainerRef}) viewcontainer; 在这里,ViewContainerRef是一个非常重要的部分,它使DOM节点成为视图容器。 1. 创建视图并将视图添加到视图容器中。 Viewcontainer.CreateEmbeddedView(TemplateRef); ### 创建一个模板 ### 它非常类似于创建视图容器。让我们看看如何创建它们。 步骤: 1. 在模板文件中添加ng-template标签。 <ng-template #t></ng-template> 1. 使用它创建一个模板。 @ViewChild(‘t’, { ‘read’: TemplateRef}) template: Templateref; 例: 模板文件: <p>parent works!</p> <ng-container #viewcontainer></ng-container> <ng-template> <app-child #child></app-child> </ng-template> <button (click)='removeChild()'>remove child</button> 类文件: @ViewChildren('child', { read: ElementRef}) childComp:QueryList<ElementRef> @ViewChild('viewcontainer', { 'read': ViewContainerRef}) viewcontainer; @ViewChild(TemplateRef) template: TemplateRef<null>; constructor(private renderer: Renderer2, private host: ElementRef) { } ngAfterViewChecked() { console.log("Child components count", this.childComp.length) } ngAfterViewInit(){ this.viewcontainer.createEmbeddedView(this.template); } removeChild(){ this.viewcontainer.remove(); } 解决方案: 这个例子只是我们问题的一个解决方案。现在,如果我们移除DOM元素,Angular会直接更新视图。 显示: \[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-agj2mTVt-1632643270012)(/Users/jiangyumin/Documents/img/result.png)\] 最后,我们做到了。我希望我们大家都明白view: 像\*ngIf, \*ngFor, \*ngSwitch这样的结构指令是基于视图容器来修改DOM结构的。 接下来,我们将使用viewContainerRef和templateRef来改变DOM结构。我们可以将呈现逻辑分离到单独的指令中,就像在修改DOM元素一节中所做的那样。这将非常有用。我们可以使用像\*ngFor, \*ngIf这样的指令. **注意**: 如果DOM元素是由Angular创建的,默认情况下视图也会被创建。如果我们使用Jquery或JavaScript直接更改DOM结构,则不会更新视图。Angular并不知道DOM元素已经创建。所以更改检测对那个DOM元素不起作用。 # 总结: # 1. 调整DOM元素–使用渲染器服务 2. 调整DOM结构–使用ViewContainerRef和TemplateRef类 3. 将呈现逻辑分离成指令。它有助于复用代码。 4. 避免使用JavaScript或Jquery直接操作DOM。尝试使用框架的可用特性。
相关 如何在Java中正确地进行异常处理? 在Java中,异常处理是一种机制,用于捕获、管理和响应程序运行时出现的错误。以下是在Java中正确进行异常处理的基本步骤: 1. **抛出异常**:当你发现某个操作可能会失败 悠悠/ 2024年09月15日 19:03/ 0 赞/ 7 阅读
相关 在Java中,如何正确地使用反射机制? 反射是Java提供的一种允许程序在运行时动态地检查类、字段和方法信息的机制。 以下是在Java中正确使用反射机制的步骤: 1. 获取Class对象:反射的主要目标是操作类或 深碍√TFBOYSˉ_/ 2024年09月13日 11:06/ 0 赞/ 17 阅读
相关 在Java中,如何正确地实现单例模式? 在Java中,实现单例模式主要有以下几种方法: 1. 饿汉式单例(Static Singleton): ```java public class Singleton { 左手的ㄟ右手/ 2024年09月13日 03:33/ 0 赞/ 17 阅读
相关 在Java中如何正确地进行文件读写操作 在Java中,文件的读写操作主要通过`FileInputStream`, `FileOutputStream`, `BufferedReader`, 和 `PrintWrite r囧r小猫/ 2024年09月11日 03:45/ 0 赞/ 34 阅读
相关 如何在Angular中正确地操作DOM ? 序 通常,当我们在Angular中使用JavaScript技术时,我们几乎会忘记框架的特性。让我们去使用它们。 web开发中一个有趣的主题是DOM操作。在Angular中 深藏阁楼爱情的钟/ 2022年09月12日 14:56/ 0 赞/ 152 阅读
相关 angular操作dom [angular.element方法汇总以及AngularJS 动态添加元素和删除元素][angular.element_AngularJS] addClass()-为每 今天药忘吃喽~/ 2022年06月02日 00:40/ 0 赞/ 179 阅读
相关 在Mac中如何正确地设置JAVA_HOME 前期准备 1. 下载JDK安装包:在[JDK1.8下载][JDK1.8]中选择Mac的JDK安装包 2. 安装JDK:这里只要按照安装指引一步一步安装即可 查找J 冷不防/ 2022年05月29日 13:45/ 0 赞/ 382 阅读
相关 Angular使用总结 --- 如何正确的操作DOM 原文出处:[https://www.cnblogs.com/shapeY/p/9272961.html][https_www.cnblogs.com_shapeY_p_9272 妖狐艹你老母/ 2022年03月22日 12:43/ 0 赞/ 161 阅读
相关 AngularJS操作DOM----angular.element AngularJs是不直接操作DOM的,但是在平时的开发当中,我们有的时候还是需要操作一些DOM的,如果使用原生的JS的话操作过于麻烦,所以大家一般都是使用jQ 电玩女神/ 2021年09月14日 06:56/ 0 赞/ 311 阅读
还没有评论,来说两句吧...