详解Angular动态组件

使用场景

我们先明确下动态组件的使用场景,在代码运行时要动态加载组件,换成普通人话,代码需要根据具体情况(比如用户的操作,向后台请求结果)确定在某些地方加载某些组件,这些组件不是静态的(不是固定的)。

官网的举例就是,构建动态广告条,广告组件不断会推出新的,再用只支持静态组件结构的模板显然是不现实的。

再举一个常见的例子,动态弹出框,弹出的组件是不确定的、不断更新的,这里那里弹出个购买框,那那那又需要弹出样式选择框,静态组件结构模板是不能满足群众日渐增长的需求。

怎么实现

然后我们来找个把手,看实现动态组件需要什么。

一、动态组件放在哪

我们需要知道把动态组件加在哪里,也就是锚点。那什么东西可以用来加载组件呢?

你可能会想说,组件不就加载锚点上吗,锚点不就是DOM节点吗?那当然是加载DOM节点里啊。

我们先来回顾下Angular操作DOM的常见方法,原生JS操作DOM的方法你就不要想了,你觉得它能返回给你能加载Angular组件的对象吗?

Angular 提供了一种叫做 DOM Query 的技术,主要来源于 @ViewChild 和 @ViewChildren 装饰器(decorators),两者基本功能相同 。

@ViewChild: 返回单个引用,在视图的 DOM 中查找能匹配上该选择器的第一个元素或指令。

@ViewChildren :返回由 QueryList 对象包装好的多个引用,在视图的 DOM 中查找能匹配上该选择器的所有元素或指令。

基本语法:

@ViewChild([reference from template], {read: [reference type]});

DOM Query 的技术查找出来的对象分为三类:

ElementRef:如果它挂载的是类似 span 的简单 html 元素;

TemplateRef: 如果它挂载的是 template 元素;

ViewContainerRef: 无法推断,一般要程序员要在read中指明,任何DOM元素都可以被用作为视图容器。

我们通过官网查询API可以看到只有ViewContainerRef才是可以将一个或多个视图附着到组件中的容器,也就是只有它才可以加载组件。不过要注意的是,它是一个可以将新的组件作为其兄弟(节点)的DOM元素(容器),是兄弟,不是父子额。

好的,我们确定了使用ViewContainerRef来加载容器,获取ViewContainerRef有两种方式:

第一种就是上面的通过DOM Query查询@ViewChild获取

<ng-container #addComp></ng-container>
@ViewChild('addComp', {read: ViewContainerRef}) adComp:ViewContainerRef;

第二种就是官网里的例子,用依赖注入

import { Directive, ViewContainerRef } from '@angular/core';

@Directive({
selector: '[ad-host]',
})
export class AdDirective {
constructor(public viewContainerRef: ViewContainerRef) { }
}

锚点设置ng-template上,通过指令注入获取ViewContainerRef

template: `
<div class="ad-banner-example">
<h3>Advertisements</h3>
<ng-template ad-host></ng-template>
</div>

二、怎么获取组件的实例

组件加载到视图中去,不是简单一个new就实例化,再append、insert之类就能附加上去的就可以的。动态组件需要编译器事先编译存放好起来,再以ComponentFactory封装起来,之后的Component实例要通过ComponentFactory 来创建。大家可以看下这篇文章[译] 关于 Angular 动态组件你需要知道的,不过它提及的使用 SystemJsNgModuleLoader 模块加载器已经被淘汰了。

ComponentFactoryResolver一个简单的注册表,映射Components到ComponentFactory可用于创建组件实例的生成的类。它可用于获取给定组件类型的工厂,然后使用工厂的create()方法创建该类型的组件。

我们来看下官网实例代码,以下不是完整代码

//注入ComponentFactoryResolver
constructor(private componentFactoryResolver: ComponentFactoryResolver) { }

loadComponent() {
......
// 拿到可用于创建广告组件实例的生成的ComponentFactory
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(adItem.component);

//获取加载组件的容器
const viewContainerRef = this.adHost.viewContainerRef;
viewContainerRef.clear();

// 把组件放到容器里,再传一些参数给它
const componentRef = viewContainerRef.createComponent(componentFactory);
(<AdComponent>componentRef.instance).data = adItem.data;
}

你以为这就完了,你以为这样写出的代码就能运行吗?太年轻,让前浪来给你说一下要注意的几个点:

Angular 中的组件、指令、管道都是是被封装在模块中,以组件为例,如果要使用其别的模块组件,必须别的模块有export这个组件,而且你在自己模块也要import其他模块。所以官网例子的指令记得导入导出。

如果是动态组件,必须把组件注册在模块中 entryComponents 属性,但是就不用了export,import模块还是需要的。

以上就是详解Angular动态组件的详细内容,更多关于Angular动态组件的资料请关注我们其它相关文章!

(0)

相关推荐

  • angular 动态组件类型详解(四种组件类型)

    组件类型1:纯函数功能,而没有视图部分,即Factory(类似于$http) promise.component.html 常见的有内置的$http,$q之类的.一般使用promise与作用域进行交互 组件类型2:不是常驻于视图,而是动态插入的.有UI的一类组件,有输入交互.不常被调用(类似于Model对话框) factory.component.html 并发性.这里收到es6的启发.在factory内使用了构造函数,来区分不同的实例.当然,factory接口返回的类型要根据需求来定:仅仅是一

  • angular6的table组件开发的实现示例

    背景及吐槽: 今年有机会再次接触angualr这个框架,想起第一次接触ng还是16年读书的时候,当时还是ng1,然后学起来特别辛苦,学习曲线特别陡峭:而今年有一个项目重构直接采用了angular6,而后面该项目后面由我负责开发和维护,然后我又重新再学习了ng6,本以为有ng1的基础,学起来会好一些,然并卵,学习的曲线特别陡峭,但还是最后将ng6啃下来(很不情愿去学的,但没办法).回归到项目,该项目没有引入其他组件库,所以很多基础组件都是自己开发(用ng开发那种酸爽很带劲),其中table组件让我

  • 浅谈angular2子组件的事件传递(任意组件事件传递)

    angular2子组件的事件传递 angular2有很多组件组成,画面由很多路由,导致事件的传递很"笨拙",本组的技术负责人发现了任意组件传递事件的这个方法,教会了我,我做个笔记. 项目情况: 画面结构复杂,路由数目偏多,组件数目多,嵌套复杂.业务要求:任何出现人名的地方,点击人名,直接打开和这个人的聊天画面 以前用angular2官网给的烹饪技巧基本解决90%的需求,当然这个如果是用Input,Output也可以,但是那样的话,结构将是混沌状态. 附:angluar2的组件通讯的传送

  • Angular7创建项目、组件、服务以及服务的使用

    三大前端项目就剩angular没学了,在网上找了几个教程,这里总结一下,方便以后用到时查阅 创建项目 首先安装cli工具 npm install -g @angular/cli 创建一个空项目, 有两处要选择的,一个是路由,我这里是要路由的,还有一个开发css的语言,我这里选择scss,就不截图了,选完后会自动通过yarn安装依赖,稍等一会就好了 ng new pybbs-front-angular 创建好了,运行 npm run start 或者 ng serve 启动服务,然后就可以在浏览器

  • angular4自定义组件非input元素实现ngModel双向数据绑定的方法

    在angular里我们一般都是给input元素添加[(ngModel)]="value"实现数据双向绑定,如果想实现自定义的组件上实现ngModel双向数据绑定应该怎么办呐... 网上找了一下,没看懂记录一下. 场景:组件能获取父组件通过ngModel绑定的值,能通过ngModel改变父组件对应的数据.如下代码: <app-child [(ngModel])="appData"></app-child> 1.先贴出效果图: 2.下面是app-

  • 详解Angular6学习笔记之主从组件

    主从组件 继学习笔记6,现在可以在页面上显示一个数组,但是原则上不能将所有特性放在同一个组件中,因为如果将所有特性放在同一个组件中,当特性特别多时,组件就变得不好维护了.所以要将大型组件拆分为多个小型组件,使每一个小型组件集中处理某一个特性任务或者工作流,而且这样也便于维护. 这次要将学习笔记6中的查看hero详情,放置在一个新的,独立,可复用的组件中,集中在新的组件管理和维护hero详情的信息. 1.创建一个新的组件 使用 Angular CLI 生成一个名叫 hero-detail 的新组件

  • angular 实现下拉列表组件的示例代码

    需求: 方案一 最开始就是用最简单的方法,前台请求数据,然后通过select和option在页面上显示,但是写了一会儿发现出现了许多类似下面的重复的代码: // 初始化年级选项 initGradeOptions() { this.gradeService.getAll().subscribe((res) => { this.gradeOptions = res; }, () => { console.log('get gradeOption error'); }); } <nz-sele

  • 详解Angular中实现自定义组件的双向绑定的两种方法

    在 Angular 中,对于表单元素,通过 [(ngModel)] 即可以简单地实现双向绑定.对于自定义组件而言,希望实现同样的效果可以怎么做呢? 1 实现自定义组件的 ngModel 指令 如果希望自定义组件能够具有与表单元素相同的 ngModel 效果,可以通过在组件内实现 ControlValueAccessor 接口达到目的. 对于 [(ngModel)] ,需要至少实现该接口的如下方法: interface ControlValueAccessor { writeValue(obj:

  • 详解Angular动态组件

    使用场景 我们先明确下动态组件的使用场景,在代码运行时要动态加载组件,换成普通人话,代码需要根据具体情况(比如用户的操作,向后台请求结果)确定在某些地方加载某些组件,这些组件不是静态的(不是固定的). 官网的举例就是,构建动态广告条,广告组件不断会推出新的,再用只支持静态组件结构的模板显然是不现实的. 再举一个常见的例子,动态弹出框,弹出的组件是不确定的.不断更新的,这里那里弹出个购买框,那那那又需要弹出样式选择框,静态组件结构模板是不能满足群众日渐增长的需求. 怎么实现 然后我们来找个把手,看

  • 详解Angular父子组件通讯

    概述 Angular组件间通讯 组件树,1号是根组件AppComponent. 组件之间松耦合,组件之间知道的越少越好. 组件4里面点击按钮,触发组件5的初始化逻辑. 传统做法:在按钮4的点击事件里调用组件5的方法.紧密耦合. Angular:在组件4根本不知道组件5存在的情况下实现. 使用松耦合的方式在组件之间传递数据开发出高重用性的组件. 使用输入输出属性在父子关系的组件之间传递数据. 一.输入输出属性概述 组件设计成黑盒模型,用输入属性声明从外部世界接收什么东西.不需要知道这些东西从哪里来

  • 详解Vue 动态组件与全局事件绑定总结

    最近在自学 Vue 也了解了一些基本用法,也记录了一些笔记有兴趣的朋友可以去查看我的其他文章,技术这东西真的不能光靠看,看是没有的,你必须要动手实践,只有在实战项目中才能发现问题,才能发现我们没有掌握的知识点,然后发现问题解决问题,我们的能力才能得以提升,要不然就有点眼高手低了. 基于这个想法于是就开始自己去撸了一个旅游网站,旅游网站嘛避免不了城市的选择,所以在实现城市选择列表的时候碰到的一些问题,以及解决办法今天就记录下来做一个总结. 城市列表选择组件 首先说说我们要实现一个什么样的城市选择组

  • 详解Angular组件之投影

    概述 运行时动态改变组件模版的内容.没路由那么复杂,只是一段html,没有业务逻辑. ngContent指令将父组件模版上的任意片段投影到子组件上. 一.简单例子 1.子组件中使用<ng-content>指令来标记投影点 <div class="wrapper"> <h2>我是子组件</h2> <div>这个div定义在子组件中</div> <ng-content></ng-content>

  • 详解Angular组件之生命周期(二)

    一.view钩子 view钩子有2个,ngAfterViewInit和ngAfterViewChecked钩子. 1.实现ngAfterViewInit和ngAfterViewChecked钩子时注意事项 以父组件调用子组件方法中例子为基础,在父组件中实现ngAfterViewInit和ngAfterViewChecked钩子. 这两个钩子是在组件的模版所有内容组装完成后,组件模版已经呈现给用户看了,之后这两个钩子方法会被调用. @ViewChild('child1') child1:Child

  • 详解Angular组件生命周期(一)

    概述 组件声明周期以及angular的变化发现机制 红色方法只执行一次. 变更检测执行的绿色方法和和组件初始化阶段执行的绿色方法是一个方法. 总共9个方法. 每个钩子都是@angular/core库里定义的接口. import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-life', templateUrl: './life.component.html', styleUrls: ['./life

  • 详解Angular组件之中间人模式

    一.中间人模式 该组件树中除了组件1以外,每个组件都有一个父组件可以扮演中间人的角色.顶级的中间人是组件1,它可以使组件2,组件3,组件6之间互相通讯.依次类推,组件2是组件4和组件5的中间人.组件3是组件7和组件8的中间人. 中间人负责从一个组件接收数据并将其传递给另一个组件. 二.例子 股票报价组件为例,假设交易员在监看着报价组件的价格,当股票价格达到某一个值的时候,交易员会点一个购买按钮,来购买股票.问题:报价组件并不知道应该如何下单来买股票,它只是用来监控股票价格的.所以报价组件在这时应

  • 详解Angular组件数据不能实时更新到视图上的问题

    目录 问题起源 OnPush策略 当前组件或子组件之一触发了事件 总结 问题起源 MainComponent: @Component({ selector: 'main', template: ` <MenuComponent [isReport]="isReport"> </MenuComponent> `, changeDetection:ChangeDetectionStrategy.OnPush }) export class MainComponent

  • 详解Angular-cli生成组件修改css成less或sass的实例

    详解Angular-cli生成组件修改css成less或sass的实例 使用cli命令生成组件: ng generate component 组件名 生成出来的组件文件有:html / ts / css / spec.ts 问题我是一个less重度患者怎么可能再去写css呢. 于是我就在想使用cli生成组件的时候能直接生成出来的是less文件而不是css文件: 修改angular-cli.json文件: apps "styles": [ "styles.less"

  • 详解Angular结构型指令模块和样式

    一,结构型指令 *是一个语法糖,<a *ngIf="user.login">退出</a>相当于 <ng-template [ngIf]="user.login"> <a>退出</a> </ng-template> 避免了写ng-template. <ng-template [ngIf]="item.reminder"> <mat-icon > alar

随机推荐