Angular's slogan is - "One & desktop. It is suitable for both mobile phones and desktops (One & desktop.)", that is, Angular supports the development of cross-platform applications, such as: Web applications, mobile Web applications, native mobile applications and native desktop applications.
In order to be able to support cross-platform, Angular encapsulates the differences between different platforms through an abstraction layer and unifies the API interface. For example, the abstract class Renderer, the abstract class RootRenderer, etc. are defined. In addition, the following reference types are defined: ElementRef, TemplateRef, ViewRef, ComponentRef, and ViewContainerRef, etc. Let’s analyze the ElementRef class below:
The role of ElementRef
Directly operating the DOM at the application layer will cause strong coupling between the application layer and the rendering layer, causing our applications to be unable to run in different environments, such as web worker, because in the web worker environment, the DOM cannot be directly operated. Interested readers can read this article about the classes and methods supported in Web Workers. Through ElementRef, we can encapsulate native elements in view layers under different platforms (in browser environments, native elements usually refer to DOM elements). Finally, with the powerful dependency injection features provided by Angular, we can easily access native elements.
Definition of ElementRef
export class ElementRef { public nativeElement: any; constructor(nativeElement: any) { = nativeElement; } }
Application of ElementRef
Let’s first introduce the overall requirements. We want to obtain the div element in the page after the page is successfully rendered and change the background color of the div element. Next, let’s take a step by step to realize this requirement.
First of all, we need to obtain the div element. In the "ElementRef" section of the article, we have mentioned that we can use the powerful dependency injection feature provided by Angular to obtain the encapsulated native elements. In the browser, the native element is the DOM element. We just need to get the my-app element first, and then use the querySelector API to get the div element in the page. The specific code is as follows:
import { Component, ElementRef } from '@angular/core'; @Component({ selector: 'my-app', template: ` <h1>Welcome to Angular World</h1> <div>Hello {{ name }}</div> `, }) export class AppComponent { name: string = 'Semlinker'; constructor(private elementRef: ElementRef) { let divEle = ('div'); (divEle); } }
Run the above code and there is no exception in the console, but the output result is null. What's going on? No exception was thrown. We can infer that this object exists, but its child element cannot be found. It should be that when the constructor is called, the child element under the my-app element has not been created yet. So how to solve this problem? In contemplation..., isn't there a setTimeout? Let's make a little change:
constructor(private elementRef: ElementRef) { setTimeout(() => { // You need to use the arrow function here, you know... let divEle = ('div'); (divEle); }, 0); }
The problem was solved, but it didn't feel very elegant? Is there a better solution? The answer is yes. Angular does not have a hook that provides component lifecycle, we can choose a suitable time and get the div element we want.
import { Component, ElementRef, AfterViewInit } from '@angular/core'; @Component({ selector: 'my-app', template: ` <h1>Welcome to Angular World</h1> <div>Hello {{ name }}</div> `, }) export class AppComponent { name: string = 'Semlinker'; // In the constructor = elementRef is optional, and the value will be automatically assigned during compilation // function AppComponent(elementRef) { = elementRef; } constructor(private elementRef: ElementRef) { } ngAfterViewInit() { // The element in the template has been created (('div')); // let greetDiv: HTMLElement = ('div'); // = 'red'; }}
After running the code above, we see the expected div element. Let's directly use the ngAfterViewInit hook, don't ask me why, because it's the most pleasing to you. However, we will also have a special article later to analyze the life cycle of Angular components in detail. After successfully obtaining the div element, the rest is easy to do. Set the background color of the element directly through the style object.
Although the functions have been implemented, is there still room for optimization?
import { Component, ElementRef, ViewChild, AfterViewInit } from '@angular/core'; @Component({ selector: 'my-app', template: ` <h1>Welcome to Angular World</h1> <div #greet>Hello {{ name }}</div> `, }) export class AppComponent { name: string = 'Semlinker'; @ViewChild('greet') greetDiv: ElementRef; ngAfterViewInit() { = 'red'; } }
Do you feel so high-end in an instant, but wait first, does the above code still have room for further optimization? We see the background of setting the div element, and we are the default application running environment in the browser. As mentioned earlier, we must minimize the strong coupling relationship between the application layer and the rendering layer, so that our applications can run flexibly in different environments. Finally, let’s take a look at the final optimized code:
import { Component, ElementRef, ViewChild, AfterViewInit, Renderer } from '@angular/core'; @Component({ selector: 'my-app', template: ` <h1>Welcome to Angular World</h1> <div #greet>Hello {{ name }}</div> `, }) export class AppComponent { name: string = 'Semlinker'; @ViewChild('greet') greetDiv: ElementRef; constructor(private elementRef: ElementRef, private renderer: Renderer) { } ngAfterViewInit() { // = 'red'; (, 'backgroundColor', 'red'); } }
What other commonly used methods are APIs?
export abstract class Renderer { // Create element abstract createElement(parentElement: any, name: string, debugInfo?: RenderDebugInfo): any; // Create text element abstract createText(parentElement: any, value: string, debugInfo?: RenderDebugInfo): any; // Set text abstract setText(renderNode: any, text: string): void; // Set element Property abstract setElementProperty(renderElement: any, propertyName: string, propertyValue: any): void; // Set the element Attribute abstract setElementAttribute(renderElement: any, attributeName: string, attributeValue: string): void; // Set the Class abstract setElementClass(renderElement: any, className: string, isAdd: boolean): void; // Set the style of the element abstract setElementStyle(renderElement: any, styleName: string, styleValue: string): void; }
It should be noted that in the Angular+ version, we use Renderer2 instead of Renderer (Angular V2).
2.What other commonly used methods are there in the Renderer2 API?
export abstract class Renderer2 { abstract createElement(name: string, namespace?: string|null): any; abstract createComment(value: string): any; abstract createText(value: string): any; abstract setAttribute(el: any, name: string, value: string, namespace?: string|null): void; abstract removeAttribute(el: any, name: string, namespace?: string|null): void; abstract addClass(el: any, name: string): void; abstract removeClass(el: any, name: string): void; abstract setStyle(el: any, style: string, value: any, flags?: RendererStyleFlags2): void; abstract removeStyle(el: any, style: string, flags?: RendererStyleFlags2): void; abstract setProperty(el: any, name: string, value: any): void; abstract setValue(node: any, value: string): void; abstract listen( target: 'window'|'document'|'body'|any, eventName: string, callback: (event: any) => boolean | void): () => void; }
The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.