https://segmentfault.com/a/1190000008695459

ViewChild

ViewChild 是属性装饰器,用来从模板视图中获取匹配的元素。视图查询在 ngAfterViewInit 钩子函数调用前完成,因此在 ngAfterViewInit 钩子函数中,才能正确获取查询的元素。

@ViewChild 使用模板变量名

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')
greetDiv: ElementRef; ngAfterViewInit() {
console.dir(this.greetDiv);
}
}

@ViewChild 使用模板变量名及设置查询条件

import { Component, TemplateRef, ViewChild, ViewContainerRef, AfterViewInit } from '@angular/core';

@Component({
selector: 'my-app',
template: `
<h1>Welcome to Angular World</h1>
<template #tpl>
<span>I am span in template</span>
</template>
`,
})
export class AppComponent { @ViewChild('tpl')
tplRef: TemplateRef<any>; @ViewChild('tpl', { read: ViewContainerRef })
tplVcRef: ViewContainerRef; ngAfterViewInit() {
console.dir(this.tplVcRef);
this.tplVcRef.createEmbeddedView(this.tplRef);
}
}

@ViewChild 使用类型查询

child.component.ts

import { Component, OnInit } from '@angular/core';

@Component({
selector: 'exe-child',
template: `
<p>Child Component</p>
`
})
export class ChildComponent {
name: string = 'child-component';
}

app.component.ts

import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from './child.component'; @Component({
selector: 'my-app',
template: `
<h4>Welcome to Angular World</h4>
<exe-child></exe-child>
`,
})
export class AppComponent { @ViewChild(ChildComponent)
childCmp: ChildComponent; ngAfterViewInit() {
console.dir(this.childCmp);
}
}

以上代码运行后,控制台的输出结果:

ViewChildren

ViewChildren 用来从模板视图中获取匹配的多个元素,返回的结果是一个 QueryList 集合。

@ViewChildren 使用类型查询

import { Component, ViewChildren, QueryList, AfterViewInit } from '@angular/core';
import { ChildComponent } from './child.component'; @Component({
selector: 'my-app',
template: `
<h4>Welcome to Angular World</h4>
<exe-child></exe-child>
<exe-child></exe-child>
`,
})
export class AppComponent { @ViewChildren(ChildComponent)
childCmps: QueryList<ChildComponent>; ngAfterViewInit() {
console.dir(this.childCmps);
}
}

以上代码运行后,控制台的输出结果:

ViewChild 详解

@ViewChild 示例

import { Component, ElementRef, ViewChild } 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')
greetDiv: ElementRef;
}

编译后的 ES5 代码片段

var core_1 = require('@angular/core');

var AppComponent = (function () {
function AppComponent() {
this.name = 'Semlinker';
}
__decorate([
core_1.ViewChild('greet'), // 设定selector为模板变量名
__metadata('design:type', core_1.ElementRef)
], AppComponent.prototype, "greetDiv", void 0);

ViewChildDecorator 接口

export interface ViewChildDecorator {
// Type类型:@ViewChild(ChildComponent)
// string类型:@ViewChild('tpl', { read: ViewContainerRef })
(selector: Type<any>|Function|string, {read}?: {read?: any}): any; new (selector: Type<any>|Function|string,
{read}?: {read?: any}): ViewChild;
}

ViewChildDecorator

export const ViewChild: ViewChildDecorator = makePropDecorator(
'ViewChild',
[
['selector', undefined],
{
first: true,
isViewQuery: true,
descendants: true,
read: undefined,
}
],
Query);

makePropDecorator函数片段

/*
* 创建PropDecorator工厂
*
* 调用 makePropDecorator('ViewChild', [...]) 后返回ParamDecoratorFactory
*/
function makePropDecorator(name, props, parentClass) {
// name: 'ViewChild'
// props: [['selector', undefined],
// { first: true, isViewQuery: true, descendants: true, read: undefined}] // 创建Metadata构造函数
var metaCtor = makeMetadataCtor(props); function PropDecoratorFactory() {
var args = [];
... // 转换arguments对象成args数组
if (this instanceof PropDecoratorFactory) {
metaCtor.apply(this, args);
return this;
}
...
return function PropDecorator(target, name) {
var meta = Reflect.getOwnMetadata('propMetadata',
target.constructor) || {};
meta[name] = meta.hasOwnProperty(name) && meta[name] || [];
meta[name].unshift(decoratorInstance);
Reflect.defineMetadata('propMetadata', meta, target.constructor);
};
var _a;
}
if (parentClass) { // parentClass: Query
PropDecoratorFactory.prototype = Object.create(parentClass.prototype);
}
...
return PropDecoratorFactory;
}

makeMetadataCtor 函数:

// 生成Metadata构造函数: var metaCtor = makeMetadataCtor(props);
// props: [['selector', undefined],
// { first: true, isViewQuery: true, descendants: true, read: undefined }]
function makeMetadataCtor(props) {
// metaCtor.apply(this, args);
return function ctor() {
var _this = this;
var args = [];
... // 转换arguments对象成args数组
props.forEach(function (prop, i) { // prop: ['selector', undefined]
var argVal = args[i];
if (Array.isArray(prop)) { // argVal: 'greet'
_this[prop[0]] = argVal === undefined ? prop[1] : argVal;
}
else {
// { first: true, isViewQuery: true, descendants: true, read: undefined }
// 合并用户参数与默认参数,设置read属性值
for (var propName in prop) {
_this[propName] =
argVal && argVal.hasOwnProperty(propName) ?
argVal[propName] : prop[propName];
}
}
});
};
}

我们可以在控制台输入 window['__core-js_shared__'] ,查看通过 Reflect API 保存后的metadata信息

接下来我们看一下编译后的 component.ngfactory.js 代码片段,查询条件 @ViewChild('greet')

我们再来看一下前面示例中,编译后 component.ngfactory.js 代码片段,查询条件分别为:

1.@ViewChild('tpl', { read: ViewContainerRef })

2.@ViewChild(ChildComponent)

通过观察不同查询条件下,编译生成的 component.ngfactory.js 代码片段,我们发现 Angular 在创建 AppComponent 实例后,会自动调用 AppComponent 原型上的 createInternal 方法,才开始创建组件中元素,所以之前我们在构造函数中是获取不到通过 ViewChild 装饰器查询的视图元素。另外,配置的视图查询条件,默认都会创建一个 jit_QueryList 对象,然后根据 read 查询条件,创建对应的实例对象,然后添加至 QueryList 对象中,然后在导出对应的查询元素到组件对应的属性中。

总结

ViewChild 装饰器用于获取模板视图中的元素,它支持 Type 类型或 string 类型的选择器,同时支持设置 read 查询条件,以获取不同类型的实例。而 ViewChildren 装饰器是用来从模板视图中获取匹配的多个元素,返回的结果是一个 QueryList 集合。

Angular 2 中的 ViewChild 和 ViewChildren的更多相关文章

  1. 一个Angular模块中可以声明哪些组件?

    一个Angular模块中可以声明哪些组件? (1) controller        控制器 (2) directive                指令 (3) function         ...

  2. Angular JS中的依赖注入

    依赖注入DI angularjs中与DI相关有angular.module().angular.injector(). $injector.$provide. DI 容器3要素:服务的注册.依赖关系的 ...

  3. 秒味课堂Angular js笔记------Angular js中的工具方法

    Angular js中的工具方法 angular.isArray angular.isDate angular.isDefined angular.isUndefined angular.isFunc ...

  4. 在 Angular 8 中,我们可以期待些什么

    转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 本文由葡萄城翻译并发布 --- Angular 作为一款优秀的前端框架,自诞生之日起,就致力于面向前端开发者 ...

  5. 在angular 6中使用 less

    在angular 6中使用 less 新项目 ng new [appname] --style less 已有的项目 修改 *.css 文件及引用处后缀名为 less并在 angular.json 文 ...

  6. (网页)Angular.js 中 copy 赋值与 = 赋值 区别

    转自st.gg Angular.js 中 copy 赋值与 = 赋值 区别 为什么用 $scope.user = $scope.master; $scope.master 会跟着 $scope.use ...

  7. angular.js 中同步视图和模型数据双向绑定,$watch $digest $apply 机制

    Angular.js 中的特性,双向绑定. 让视图的改变直接反应到数据中,数据的改变又实时的通知到视图,如何做到的? 这要归功于 scope 下面3个重要的方法: $watch $digest $ap ...

  8. angular.js 中的作用域 数据模型 控制器

    1.angular.js 作为后起之秀的前端mvc框架,他于传统的前端框架都不同,我们再也不需要在html中嵌入脚本来操作对象了.它抽象出了数据模型,控制器及视图. 成功解耦了应用逻辑,数据模型,视图 ...

  9. angular开发中的两大问题

    一.在我们的angular开发中,会请求数据但轮播图等...在请求过数据后他的事件和方法将不再执行: 看我们的解决方案一: app.controller("text",functi ...

随机推荐

  1. spring4-2-bean配置-1-依赖注入

    配置 bean,本章节中主要介绍蓝色文字部分. 配置形式:基于 XML 文件的方式:基于注解的方式 Bean 的配置方式:通过全类名(反射).通过工厂方法(静态工厂方法 & 实例工厂方法).F ...

  2. Python 执行js的2种解决方案-乾颐堂

    第1种方案 SpiderMonkey是Mozilla项目的一部分,是一个用C语言实现的JavaScript脚本引擎, 该引擎分析.编译和执行脚本,根据JS数据类型和对象的需要进行内存分配及释放操作:利 ...

  3. TensorFlow全新的数据读取方式:Dataset API入门教程

    TensorFlow.data : http://tech.ifeng.com/a/20171109/44752505_0.shtml Pytorch:https://ptorch.com/docs/ ...

  4. Linux发送邮件

    以下是自己收集的实用Linux下简单配置外部邮箱发送邮件的方法: 1.配置/etc/mail.rc,使用mail命令 # vim /etc/mail.rc ###调用外部邮箱   set from=t ...

  5. list<?>转换成 对应的 class

    项目中用到的,list转换成bean.因为查询出来的数据用list 泛型接收,要返回 实体对象.所以需要对应转换. 主要用到的技术:反射. 上代码: public static <T> L ...

  6. javascript总结34 :DOM之节点元素获取

    常用节点元素获取: 1. 获取 html -- > document.documentElement 2. 获取 body -- > document.body 3. 获取指定的元素 -- ...

  7. Params应用

    有时候我们要想传递可变数量的参数改怎么办??Params给我们提供了一个很好的方法 Parmas: 1.只运用方法的最后一位参数 2.这个参数只能标志任意类型的一位数组 3.添加了params这个参数 ...

  8. vs下C# WinForm 解决方案里面生成的文件都是什么作用?干什么的?

    Properties文件夹 定义你程序集的属性 项目属性文件夹 一般只有一个 AssemblyInfo.cs 类文件,用于保存程序集的信息,如名称,版本等,这些信息一般与项目属性面板中的数据对应,不需 ...

  9. Java对称加密算法

    对称加密算法概念 加密密钥和解密密钥相同,大部分算法加密揭秘过程互逆. 特点:算法公开.(相比非对称加密)计算量小.加密速度快.效率高. 弱点:双方都使用同样的密钥,安全性得不到保证. 常用对称加密算 ...

  10. LinearLayout属性用法和源码分析

    转载自:http://www.jianshu.com/p/650c3fd7e6ab   一. LinearLayout的属性和用法 LinearLayout对于开发来说,是使用最常用的布局控件之一,但 ...