angular的ElementRef和Renderer2

2023-11-07

Angular ElementRef 简介
angular angular 2018/09/22
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 createText(value: string): any;

// 创建Comment元素
abstract createComment(value: string): any;

// 设置元素Property属性
abstract setProperty(el: any, name: string, value: any): void;

// 设置元素Attribute属性
abstract setAttribute(el: any, name: string, value: string,
namespace?: string|null): void;

// 设置元素Class类
abstract addClass(el: any, name: string): void;

// 设置元素的样式
abstract setStyle(el: any, style: string, value: any,
flags?: RendererStyleFlags2): void;
}**

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

angular的ElementRef和Renderer2 的相关文章

随机推荐

  • 前端WebSocket详解

    websocket是H5才开始提供的一种在单个TCP连接上进行全双工通讯的协议 主要作用就是建立服务器和客户端的长连接能更好的节省服务器资源和带宽 服务器向浏览器推流实现实时通信 复制代码 和http一样 WebSocket也是应用层协议
  • mysql create trigger 触发器已存在

    1 CREATE TRIGGER 时显示触发器以存在 2 DROP TRIGGER IF EXISTS 也失败 解决 1 通过my ini 查到 datadir的路径 找到数据文件路径 2 找到相关数据库目录 删除相关触发器文件 如触发器名
  • eclipse_cpp 配置mingw

    1 MinGW 5 1 6的安装 首先下载 然后双击安装 过程如下 这一步如果你只想用Eclipse编译C C程序的话 只选上面三项即可 当然你可以都安装上 接下来就等着慢慢下载和安装吧 如果你的网速比较快的话 那么你是非常幸运的 2 配置
  • 宽度优先搜索(BFS)详解,以及双向广搜

    百度百科的官方解释 宽度优先搜索算法 又称广度优先搜索 是最简便的图的搜索算法之一 这一算法也是很多重要的图的算法的原型 Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想 其别名又叫BFS 属于一种盲
  • td 字典表_mysql常用字典表(完整版)

    本节内容 mysql数据库中的常用字典表 1 显示数据库列表 复制代码 代码示例 mysql gt show databases 说明 其中字典库是 information schema 其中常用字典表 INFORMATION SCHEMA
  • java 面向对象编程 --- 类及类的成员

    目录 学习面向对象内容的三条主线 面向过程与面向对象 面向过程 POP 与 面向对象 OOP 面向对象的三大特征 例子 人把大象装进冰箱 面向对象的思想概述 类和对象 面向对象的思想概述 Java类及类的成员 类的语法格式 创建Java自定
  • SqlServer千万级以上的数据表查询优化方案《冷热数据库分离》的思路

    1 是分库而不是分表 分表即需要考虑引入分表算法 又影响后续查询 2 热数据只占全部数据的一部分 因此每次优先查询热库 以下情况才查询冷库 a 当查询条件未命中 结果集为空 时 查询冷库 b 当查询条件部分命中时 查询冷库 3 为了区分部分
  • Android解决问题的思路

    1 前言 授人以鱼不如授人以渔 当向别人请教了问题且被解答了疑惑后 或许也想知道对方是如何思考 如何按照一定的的逻辑得出最终的答案 故想分享一下我这6年Android开发中是如何解决问题的 一家之言 请同学们多多指教 2 指导性原则 第一点
  • Java通过反射运用自定义注解案例

    Java和大数据系列 注 大家觉得博客好的话 别忘了点赞收藏呀 本人每周都会更新关于人工智能和大数据相关的内容 内容多为原创 Python Java Scala SQL 代码 CV NLP 推荐系统等 Spark Flink Kafka H
  • nvcc fatal : A single input file is required for a non-link phase when an outputfile is specified

    nvcc fatal A single input file is required for a non link phase when an outputfile is specified 错误原因 我想用VS编译colmap3 8 于是
  • Android无埋点数据收集SDK关键技术解析

    前言 本文基于网易乐得无埋点数据收集SDK 无埋点数据收集SDK用于向大数据平台提供全量 完整 准确的客户端数据 Android端无埋点数据收集SDK实现中涉及到比较关键的技术点有 用字节码插桩的方式实现Android端的AOP Hook
  • 自学python记录001-使用PyCharm创建项目

    启动PyCharm后如下所示 点击新建项目 选择项目存放路径 可以勾选创建main py文件 点击创建 创建完成后可以看到main py里面有一些提示的代码 比如说Shift F10可以运行项目 Ctrl F8可以直接添加断点 双击Shif
  • 强烈推荐的机器学习,深度学习课程以及python库

    本文知乎链接 强烈推荐的机器学习 深度学习课程以及python库 本着两条原则发一波车 1 不建议报辅导班 不是因为我们不应该为学习知识付费 而是因为有更好的资源 而这些资源恰好免费 报辅导班学习浪费钱倒是次要的 主要是时间有限 所以我们要
  • 程序分析技术理解(一)

    1 基本块 Basic Block 和流图 flow graph 将一段程序划分为基本块 Basic Block BB 每个基本块满足以下条件 a 控制流只能从基本块的第一个指令进入 b 除了基本块的最后一条指令 控制流在离开基本块前不会停
  • 移动端代码质量管理与安全检测评估

    在前面的文章中已经详细介绍过Jenkins Sonarqube的安装 配置及使用 对于Web端的代码质量管理通常相对容易 Jenkins配套Sonarqube很方便就能搞定 但是对于移动端来说 尤其iOS 集成和使用的复杂性会大幅提高 目前
  • PostgreSQL系列1:PostgreSQL 10.23 离线安装

    1 安装前准备 1 1创建用户 useradd postgres passwd postgres 1 2创建数据目录和日志目录 mkdir p data db pg data mkdir p data db pg logs chown R
  • 字符串分割(split),将字符串按照指定字符进行分割。split(String regex)和split(String regex, int limit)

    一 split String regex 字符串分割 将字符串按照指定字符进行分割 返回的是一个字符串数组 public String split String regex return split regex 0 原理 参数名称是rege
  • 【狂神说Java】HTML快速入门

    目录 1 初识HTML 2 网页基本信息 3 网页基本标签 4 图像标签 5 超链接标签应用 6 行内元素和块元素 7 列表标签 8 表格标签 9 媒体元素 10 页面结构分析 11 iframe内联框架 12 初始表单post和get提交
  • 两台linux文件拷贝

    scp就是secure copy 是用来进行远程文件拷贝的 数据传输使用ssh1 并且和ssh1使用相同的认证方式 提供相同的安全保证 与rcp不同的是 scp会要求你输入密码如果需要的话 最简单的应用如下 scp 本地用户名 IP地址 文
  • angular的ElementRef和Renderer2

    Angular ElementRef 简介 angular angular 2018 09 22 Angular 的口号是 一套框架 多种平台 同时适用手机与桌面 One framework Mobile desktop 即 Angular