Angular ElementRef简介及其使用

Angular 的口号是 - “一套框架,多种平台。同时适用手机与桌面 (One framework.Mobile & desktop.)”,即 Angular 是支持开发跨平台的应用,比如:Web 应用、移动 Web 应用、原生移动应用和原生桌面应用等。

为了能够支持跨平台,Angular 通过抽象层封装了不同平台的差异,统一了 API 接口。如定义了抽象类 Renderer 、抽象类 RootRenderer 等。此外还定义了以下引用类型:ElementRef、TemplateRef、ViewRef 、ComponentRef 和 ViewContainerRef 等。

下面我们就来分析一下 ElementRef 类:

ElementRef 的作用

在应用层直接操作 DOM,就会造成应用层与渲染层之间强耦合,导致我们的应用无法运行在不同环境,如 web worker 中,因为在 web worker 环境中,是不能直接操作 DOM。有兴趣的读者,可以阅读一下 [Web Workers 中支持的类和方法][1] 这篇文章。通过 ElementRef 我们就可以封装不同平台下视图层中的 native 元素 (在浏览器环境中,native 元素通常是指 DOM 元素),最后借助于 Angular 提供的强大的依赖注入特性,我们就可以轻松地访问到 native 元素。

ElementRef 的定义

// angular-master/packages/core/src/linker/element_ref.ts
export class ElementRef<T = any> {
 public nativeElement: T;
 constructor(nativeElement: T) { this.nativeElement = nativeElement; }
}

ElementRef 的应用

我们先来介绍一下整体需求,我们想在页面成功渲染后,获取页面中的 div 元素,并改变该 div 元素的背景颜色。接下来我们来一步步,实现这个需求。

首先我们要先获取 div 元素,在文中 “ElementRef 的作用” 部分,我们已经提到可以利用 Angular 提供的强大的依赖注入特性,获取封装后的 native 元素。在浏览器中 native 元素就是 DOM 元素,我们只要先获取 my-app元素,然后利用 querySelector API 就能获取页面中 div 元素。具体代码如下:

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 = this.elementRef.nativeElement.querySelector('div');
  console.dir(divEle);
 }
}

运行上面代码,在控制台中没有出现异常,但是输出的结果却是 null 。什么情况 ? 没有抛出异常,我们可以推断 this.elementRef.nativeElement 这个对象是存在,但却找不到它的子元素,那应该是在调用构造函数的时候,my-app 元素下的子元素还未创建。

那怎么解决这个问题呢 ?沉思中… ,不是有 setTimeout 么,我们在稍微改造一下:

constructor(private elementRef: ElementRef) {
 setTimeout(() => { // 此处需要使用箭头函数哈,你懂的...
   let divEle = this.elementRef.nativeElement.querySelector('div');
   console.dir(divEle);
  }, 0);
}

更新一下代码,此时控制台成功输出了 div 。为什么添加个 setTimeout 就能成功获取到想要的 div 元素呢?此处就不展开了,有兴趣的读者可以参考 - [What the heck is the event loop anyway?][2] 这个演讲的示例。

问题解决了,但感觉不是很优雅 ?有没有更好的方案,答案是肯定的。Angular 不是有提供组件生命周期的钩子,我们可以选择一个合适的时机,然后获取我们想要的 div 元素。

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';

 // 在构造函数中 this.elementRef = elementRef 是可选的,编译时会自动赋值
 // function AppComponent(elementRef) { this.elementRef = elementRef; }
 constructor(private elementRef: ElementRef) { } 

 ngAfterViewInit() { // 模板中的元素已创建完成
  console.dir(this.elementRef.nativeElement.querySelector('div'));
  // let greetDiv: HTMLElement = this.elementRef.nativeElement.querySelector('div');
  // greetDiv.style.backgroundColor = 'red';
 }
}

运行一下上面的代码,我们看到了意料中的 div 元素。我们直接选用 ngAfterViewInit 这个钩子,不要问我为什么,因为它看得最顺眼咯。不过我们后面也会有专门的文章,详细分析一下 Angular 组件的生命周期。成功取到 div 元素,就剩下的事情就好办了,直接通过 style 对象设置元素的背景颜色。

功能虽然已经实现了,但还有优化的空间么?当然有咯!其实在 Angular 框架内部已经为我们提供了解决方案,它为我们提供了内置的装饰器,如 @ContentChild、 @ContentChildren、@ViewChild、@ViewChildren 等。

具体使用示例如下:

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() {
  this.greetDiv.nativeElement.style.backgroundColor = 'red';
 }
}

是不是感觉瞬间高大上了,不过先等等,上面的代码是不是还有进一步的优化空间呢 ?我们看到设置 div 元素的背景,我们是默认应用的运行环境在是浏览器中。前面已经介绍了,我们要尽量减少应用层与渲染层之间强耦合关系,从而让我们应用能够灵活地运行在不同环境。

最后我们来看一下,最终优化后的代码:

import { Component, ElementRef, ViewChild, AfterViewInit, Renderer2 } 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: Renderer2) { }

 ngAfterViewInit() {
  // this.greetDiv.nativeElement.style.backgroundColor = 'red';
  this.renderer.setStyle(this.greetDiv.nativeElement, 'backgroundColor', 'red');
 }
}

最后我们通过 Renderer2 实例提供的 API 优雅地设置了 div 元素的背景颜色。

我有话说

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;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Angular4 ElementRef的应用

    Angular 的口号是 - "一套框架,多种平台.同时适用手机与桌面 (One framework.Mobile & desktop.)",即 Angular 是支持开发跨平台的应用,比如:Web 应用.移动 Web 应用.原生移动应用和原生桌面应用等. 为了能够支持跨平台,Angular 通过抽象层封装了不同平台的差异,统一了 API 接口.如定义了抽象类 Renderer .抽象类 RootRenderer 等.此外还定义了以下引用类型:ElementRef.Templa

  • Angular ElementRef简介及其使用

    Angular 的口号是 - "一套框架,多种平台.同时适用手机与桌面 (One framework.Mobile & desktop.)",即 Angular 是支持开发跨平台的应用,比如:Web 应用.移动 Web 应用.原生移动应用和原生桌面应用等. 为了能够支持跨平台,Angular 通过抽象层封装了不同平台的差异,统一了 API 接口.如定义了抽象类 Renderer .抽象类 RootRenderer 等.此外还定义了以下引用类型:ElementRef.Templa

  • Angular 4 指令快速入门教程

    本系列教程的开发环境及开发语言: Angular 4 + Angular CLI TypeScript 基础知识 Angular CLI 基本使用 安装 Angular CLI (可选) npm install -g @angular/cli 创建新的项目 ng new PROJECT-NAME 启动本地服务器 cd PROJECT-NAME ng serve Angular 指令简介 Angular 的指令分为三种: 组件(Component directive):用于构建UI组件,继承于

  • 详解Angular 4 表单快速入门

    基础知识 Angular CLI 基本使用 安装 Angular CLI (可选) npm install -g @angular/cli 创建新的项目 ng new PROJECT-NAME 启动本地服务器 cd PROJECT-NAME ng serve Angular Forms 简介 Angular 4 中有两种表单: Template Driven Forms - 模板驱动式表单 (类似于 AngularJS 1.x 中的表单 ) Reactive Forms - 响应式表单 本文主要

  • Angular2开发环境搭建教程之VS Code

    前言 VSCode是微软推出的一款轻量编辑器,采取了和VS相同的UI界面,搭配合适的插件可以优化前端开发的体验. 布局:左侧是用于展示所要编辑的所有文件和文件夹的文件管理器,依次是`资源管理器`,`搜索`,`GIT`,`调试`,`插件`,右侧是打开文件的编辑区域,最多可同时打开三个编辑区域到侧边. 底栏:依次是`Git Branch`,`error&warning`,`编码格式`等. 一.设置开发环境Node  Js Angular2开发环境主要依赖Node Js和Npm, 需要node 6.9

  • Angular 4依赖注入学习教程之简介(一)

    学习目录 Angular 4 依赖注入教程之一 依赖注入简介 Angular 4 依赖注入教程之二 组件服务注入 Angular 4 依赖注入教程之三 ClassProvider的使用 Angular 4 依赖注入教程之四 FactoryProvider的使用 Angular 4 依赖注入教程之五 FactoryProvider配置依赖对象 Angular 4 依赖注入教程之六 Injectable 装饰器 Angular 4 依赖注入教程之七 ValueProvider的使用 Angular

  • angular简介和其特点介绍

    以前开发(web或者移动端)前端主要使用jQuery+原生js,如果使用某些前端UI框架的话,它自己还可能提供一些API可以使用.而且目前很多UI框架都是基于jQuery的,所以说一下由jQuery跨到angularjs跨度较大,研究了一段时间的angularjs ,下面从整体上说说感受吧: 关于和jquery的比较 首先angular是一个mvc框架,它与jquery不同之处在于,前者致力于mvc代码解耦,采用model,controller以及view方式去组织代码,而后者提供给你了很多AP

  • Angular框架详解之视图抽象定义

    前言 作为"为大型前端项目"而设计的前端框架,Angular 其实有许多值得参考和学习的设计,本系列主要用于研究这些设计和功能的实现原理.本文主要围绕 Angular 中与视图有关的一些定义进行介绍. Angular 中的视图抽象 Angular 版本可在不同的平台上运行:在浏览器中.在移动平台上或在 Web Worker 中.因此,需要特定级别的抽象来介于平台特定的 API 和框架接口之间. Angular 中通过抽象封装了不同平台的差异,并以下列引用类型的形式出现:ElementR

  • 基于angular实现模拟微信小程序swiper组件

    这段时间的主业是完成一个家政类小程序,终于是过审核发布了.不得不说微信的这个小程序生态还是颇有想法的,抛开他现有的一些问题不说,其提供的组件系统乍一看还是蛮酷的.比如其提供的一个叫swiper的视图组件,就可以在写界面的时候省不少时间和代码,轮播图片跟可滑动列表都可以用.导致现在回来写angular项目时也想整一个这样的组件出来,本文就将使用angular的组件能力和服务能力完成这么一个比较通用,耦合度较低的swiper出来. 首先要选择使用的技术,要实现的是与界面打交道的东西,自然是实现成一个

  • 详解如何在Angular中快速定位DOM元素

    在使用Angular2+中,经常会想快速的去选择DOM上的某个元素,如果是刚上手Angular,有可能直接就使用原生DOM操作或者导入jQuery再进行DOM操作,既然都使用了Angular了,有没有更好的方法呢?答案是肯定的. 通过ElementRef 先上代码: import {Component, ElementRef, OnInit} from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.

  • 简介可以自动完成UI的AngularJS工具angular-smarty

    我们最近为我们的论坛增加了一个自动完成功能(称为Smarty),在要求专业人员简介的主页上.这是一个超有用的功能,因为它有助于我们将用户导航到他们真正想去的地方.它很有意思,也是用AngularJS构建的! 我们希望Smarty能够: 通过用户的给定输入 (一个前缀),通过一个HTTP请求后自动提供建议 显示一个建议的下拉列表 当用户输入时更新 足够快,能够跟得上用户的输入 导航直观且能够关闭 可重用 以往没有AngularJS的经验,这个项目是我使用这个框架的入门项目.它真的成为了一次宝贵的学

随机推荐