本篇文章主要介紹了Angular4 ElementRef的應用,現在分享給大家,也給大家做個參考。
Angular 的口號是- "一套框架,多種平台。同時適用手機與桌面(One framework.Mobile & desktop.)",即Angular 是支援開發跨平台的應用,例如:Web 應用、行動Web 應用程式、原生行動應用程式和原生桌面應用程式等。
為了能夠支援跨平台,Angular 透過抽象層封裝了不同平台的差異,統一了 API 介面。如定義了抽象類別 Renderer 、抽象類別 RootRenderer 等。另外也定義了以下參考類型:ElementRef、TemplateRef、ViewRef 、ComponentRef 和 ViewContainerRef 等。下面我們就來分析ElementRef 類別:
在應用程式層直接操作DOM,就會造成應用層與渲染層之間強耦合,導致我們的應用無法運作在不同環境,如web worker 中,因為在web worker 環境中,就是無法直接操作DOM。有興趣的讀者,可以閱讀 Web Workers 中支援的類別和方法 這篇文章。透過ElementRef 我們就可以封裝不同平台下視圖層中的native 元素(在瀏覽器環境中,native 元素通常是指DOM 元素),最後借助於Angular 提供的強大的依賴注入特性,我們就可以輕鬆地訪問到native 元素。
export class ElementRef { public nativeElement: any; constructor(nativeElement: any) { this.nativeElement = nativeElement; } }
我們先來介紹整體需求,我們想要在頁面成功渲染後,取得頁面中的p 元素,並改變該p 元素的背景顏色。接下來我們來一步步,實現這個需求。
首先我們要先取得 p 元素,在文中 "ElementRef 的作用" 部分,我們已經提到可以利用 Angular 提供的強大的依賴注入特性,取得封裝後的 native 元素。在瀏覽器中 native 元素就是 DOM 元素,我們只要先取得 my-app元素,然後利用 querySelector API 就能取得頁面中 p 元素。具體程式碼如下:
import { Component, ElementRef } from '@angular/core'; @Component({ selector: 'my-app', template: ` <h1>Welcome to Angular World</h1> <p>Hello {{ name }}</p> `, }) export class AppComponent { name: string = 'Semlinker'; constructor(private elementRef: ElementRef) { let pEle = this.elementRef.nativeElement.querySelector('p'); console.dir(pEle); } }
執行上面程式碼,在控制台中沒有出現異常,但是輸出的結果卻是 null 。什麼情況 ?沒有拋出異常,我們可以推斷 this.elementRef.nativeElement 這個物件是存在,但卻找不到它的子元素,那應該是在呼叫建構函式的時候,my-app 元素下的子元素還未建立。那要怎麼解決這個問題呢 ?沉思中… ,不是有 setTimeout 麼,我們在稍微改造一下:
constructor(private elementRef: ElementRef) { setTimeout(() => { // 此处需要使用箭头函数哈,你懂的... let pEle = this.elementRef.nativeElement.querySelector('p'); console.dir(pEle); }, 0); }
問題解決了,但感覺不是很優雅 ?有沒有更好的方案,答案是肯定的。 Angular 不是有提供元件生命週期的鉤子,我們可以選擇一個合適的時機,然後取得我們想要的 p 元素。
import { Component, ElementRef, AfterViewInit } from '@angular/core'; @Component({ selector: 'my-app', template: ` <h1>Welcome to Angular World</h1> <p>Hello {{ name }}</p> `, }) export class AppComponent { name: string = 'Semlinker'; // 在构造函数中 this.elementRef = elementRef 是可选的,编译时会自动赋值 // function AppComponent(elementRef) { this.elementRef = elementRef; } constructor(private elementRef: ElementRef) { } ngAfterViewInit() { // 模板中的元素已创建完成 console.dir(this.elementRef.nativeElement.querySelector('p')); // let greetp: HTMLElement = this.elementRef.nativeElement.querySelector('p'); // greetp.style.backgroundColor = 'red'; } }
運行一下上面的程式碼,我們看到了意料中的 p 元素。我們直接選用 ngAfterViewInit 這個鉤子,不要問我為什麼,因為它看得最順眼咯。不過我們後面也會有專門的文章,詳細分析 Angular 組件的生命週期。成功取到 p 元素,就剩下的事情就好辦了,直接透過 style 物件設定元素的背景顏色。
功能雖然已經實現了,但還有優化的空間麼?
import { Component, ElementRef, ViewChild, AfterViewInit } from '@angular/core'; @Component({ selector: 'my-app', template: ` <h1>Welcome to Angular World</h1> <p #greet>Hello {{ name }}</p> `, }) export class AppComponent { name: string = 'Semlinker'; @ViewChild('greet') greetp: ElementRef; ngAfterViewInit() { this.greetp.nativeElement.style.backgroundColor = 'red'; } }
是不是感覺瞬間高大上了,不過先等等,上面的程式碼是不是還有進一步的最佳化空間呢 ?我們看到設定 p 元素的背景,我們是預設應用的運行環境在是瀏覽器中。前面已經介紹了,我們要盡量減少應用層與渲染層之間強耦合關係,讓我們應用能夠靈活地運行在不同環境中。最後我們來看一下,最終優化後的程式碼:
import { Component, ElementRef, ViewChild, AfterViewInit, Renderer } from '@angular/core'; @Component({ selector: 'my-app', template: ` <h1>Welcome to Angular World</h1> <p #greet>Hello {{ name }}</p> `, }) export class AppComponent { name: string = 'Semlinker'; @ViewChild('greet') greetp: ElementRef; constructor(private elementRef: ElementRef, private renderer: Renderer) { } ngAfterViewInit() { // this.greetp.nativeElement.style.backgroundColor = 'red'; this.renderer.setElementStyle(this.greetp.nativeElement, 'backgroundColor', 'red'); } }
export abstract class Renderer { // 创建元素 abstract createElement(parentElement: any, name: string, debugInfo?: RenderDebugInfo): any; // 创建文本元素 abstract createText(parentElement: any, value: string, debugInfo?: RenderDebugInfo): any; // 设置文本 abstract setText(renderNode: any, text: string): void; // 设置元素Property abstract setElementProperty(renderElement: any, propertyName: string, propertyValue: any): void; // 设置元素Attribute abstract setElementAttribute(renderElement: any, attributeName: string, attributeValue: string): void; // 设置元素的Class abstract setElementClass(renderElement: any, className: string, isAdd: boolean): void; // 设置元素的样式 abstract setElementStyle(renderElement: any, styleName: string, styleValue: string): void; }
要注意的是在 Angular 4.x 版本,我們使用 Renderer2 取代 Renderer (Angular V2)。
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; }
上面是我整理給大家的,希望今後會對大家有幫助。
相關文章:
關於在使用vue.js標籤屬性中插入變數參數的方法(詳細教學)
以上是在Angular4中如何使用ElementRef應用的詳細內容。更多資訊請關注PHP中文網其他相關文章!