Angular 动态组件

实现步骤

  • Directive
  • HostComponent
  • 动态组件
  • AdService
  • 配置AppModule
  • 需要了解的概念

Directive

  • 我们需要一个Directive来标记动态组件是在哪个容器组件内部进行渲染的。
  • 这个Directive可以获取对容器组件的引用。
  • 仅此而已。
import { Directive, ViewContainerRef } from '@angular/core';

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

HostComponent

  • 我们需要一个容器组件,所有动态组件都是在这个容器组件中创建,销毁,重新创建。。。
  • 需要将动态组件需要展示的数据和动态组件进行绑定。
import { Component, Input, AfterViewInit, ViewChild, ComponentFactoryResolver, OnDestroy } from '@angular/core';

import { AdDirective } from './ad.directive';
import { AdItem } from './ad-item';
import { AdComponent } from './ad.component'; @Component({
selector: 'app-add-banner',
template: `
<div class="ad-banner">
<h3>Advertisements</h3>
<!-- hostElement 在此! -->
<ng-template appAd></ng-template>
</div>
`
})
export class AdBannerComponent implements AfterViewInit, OnDestroy {
@Input() ads: AdItem[];
currentAddIndex: number = -1;
@ViewChild(AdDirective) adHost: AdDirective;
subscription: any;
interval: any; constructor(private componentFactoryResolver: ComponentFactoryResolver) { } // 在 view 初始化结束后才开始创建动态组件
ngAfterViewInit() {
this.loadComponent();
this.getAds();
} ngOnDestroy() {
clearInterval(this.interval);
} loadComponent() {
this.currentAddIndex = (this.currentAddIndex + 1) % this.ads.length;
let adItem = this.ads[this.currentAddIndex]; // 这里使用了工厂模式。其实Angular对于模板中出现的每一个Component都会创建一个ComponentFactory。在创建销毁时
// 实际上使用的是组件工厂来创建组件的新实例。
let componentFactory = this.componentFactoryResolver.resolveComponentFactory(adItem.component); let viewContainerRef = this.adHost.viewContainerRef;
viewContainerRef.clear();
// 传入对应的组件工厂来创建新的组件,并保存新组建的引用。
let componentRef = viewContainerRef.createComponent(componentFactory);
// 绑定数据
(<AdComponent>componentRef.instance).data = adItem.data;
} getAds() {
this.interval = setInterval(() => {
this.loadComponent();
}, 3000);
}
}
// add-item.ts
import { Type } from '@angular/core'; export class AdItem {
constructor(public component: Type<any>, public data: any) {}
}
// ad.component.ts
export interface AdComponent {
data: any;
}

在AppComponent 中使用

// app.component.ts

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

import { AdService }         from './ad.service';
import { AdItem } from './ad-item'; @Component({
selector: 'app-root',
template: `
<div>
<app-add-banner [ads]="ads"></app-add-banner>
</div>
`
})
export class AppComponent implements OnInit {
ads: AdItem[]; constructor(private adService: AdService) {} ngOnInit() {
this.ads = this.adService.getAds();
}
}

创建动态组件

// hero-job-ad.component.ts
import { Component, Input } from '@angular/core'; import { AdComponent } from './ad.component'; @Component({
template: `
<div class="job-ad">
<h4>{{data.headline}}</h4>
{{data.body}}
</div>
`
})
export class HeroJobAdComponent implements AdComponent {
@Input() data: any; }
// hero-profile.component.ts
import { Component, Input } from '@angular/core'; import { AdComponent } from './ad.component'; @Component({
template: `
<div class="hero-profile">
<h3>Featured Hero Profile</h3>
<h4>{{data.name}}</h4>
<p>{{data.bio}}</p> <strong>Hire this hero today!</strong>
</div>
`
})
export class HeroProfileComponent implements AdComponent {
@Input() data: any;
}

创建service

import { Injectable }           from '@angular/core';

import { HeroJobAdComponent }   from './hero-job-ad.component';
import { HeroProfileComponent } from './hero-profile.component';
import { AdItem } from './ad-item'; @Injectable()
export class AdService {
getAds() {
return [
new AdItem(HeroProfileComponent, {name: 'Bombasto', bio: 'Brave as they come'}), new AdItem(HeroProfileComponent, {name: 'Dr IQ', bio: 'Smart as they come'}), new AdItem(HeroJobAdComponent, {headline: 'Hiring for several positions',
body: 'Submit your resume today!'}), new AdItem(HeroJobAdComponent, {headline: 'Openings in all departments',
body: 'Apply today'}),
];
}
}

配置 AppModule

// app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { HeroJobAdComponent } from './hero-job-ad.component';
import { AdBannerComponent } from './ad-banner.component';
import { HeroProfileComponent } from './hero-profile.component';
import { AdDirective } from './ad.directive';
import { AdService } from './ad.service'; @NgModule({
imports: [ BrowserModule ],
providers: [AdService],
declarations: [ AppComponent,
AdBannerComponent,
HeroJobAdComponent,
HeroProfileComponent,
AdDirective ],
// 注意这里,需要手动引入动态组件的class,放入 entryComponents数组中,这样
// Angular才能为动态组件创建组件工厂。如果不写,Angular在模板中不会发现这两个组件的具体引用,
// 可能在打包时将组件代码排除。
entryComponents: [ HeroJobAdComponent, HeroProfileComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule {
constructor() {}
}
ng serve

完成。

需要了解的概念

  • ViewContainerRef
  • ViewChild
  • ComponentFactoryResolver
  • ComponentFactory
  • ComponentRef

Angular 动态组件的更多相关文章

  1. Angular动态组件

    一.主页面: app.component.html: <button (click)="load();">动态</button> 2<div #dom ...

  2. angular 动态组件类型

    出处:https://github.com/Penggggg/angular-component-practices 组件类型1:纯函数功能,而没有视图部分,即Factory(类似于$http) pr ...

  3. Angular 学习笔记 (动态组件 & Material Overlay & Dialog 分析)

    更新: 2019-11-24  dialog vs router link refer : https://stackoverflow.com/questions/51821766/angular-m ...

  4. Angular动态创建组件之Portals

    这篇文章主要介绍使用Angular api 和 CDK Portals两种方式实现动态创建组件,另外还会讲一些跟它相关的知识点,如:Angular多级依赖注入.ViewContainerRef,Por ...

  5. angular2 学习笔记 ( Dynamic Component 动态组件)

    更新 2018-02-07 详细讲一下 TemplateRef 和 ViewContainerRef 的插入 refer : https://segmentfault.com/a/1190000008 ...

  6. vuejs动态组件给子组件传递数据

    vuejs动态组件给子组件传递数据 通过子组件定义时候的props可以支持父组件给子组件传递数据,这些定义的props在子组件的标签中使用绑定属性即可,但是如果使用的是<component> ...

  7. C++ 类的动态组件化技术

    序言: N年前,我们曾在软件开发上出现了这样的困惑,用VC开发COM组件过于复杂,用VB开发COM组件发现效率低,而且不能实现面向对象的很多特性,例如,继承,多态等.更况且如何快速封装利用历史遗留的大 ...

  8. Hibernate学习---第五节:普通组件和动态组件

    一.普通组件映射配置 1.创建组件类,代码如下: package learn.hibernate.bean; /** * 组件类 */ public class Phones { private St ...

  9. vue2入坑随记(二) -- 自定义动态组件

    学习了Vue全家桶和一些UI基本够用了,但是用元素的方式使用组件还是不够灵活,比如我们需要通过js代码直接调用组件,而不是每次在页面上通过属性去控制组件的表现.下面讲一下如何定义动态组件. Vue.e ...

随机推荐

  1. java并发编程——并发容器

    概述 java cocurrent包提供了很多并发容器,在提供并发控制的前提下,通过优化,提升性能.本文主要讨论常见的并发容器的实现机制和绝妙之处,但并不会对所有实现细节面面俱到. 为什么JUC需要提 ...

  2. Zigbee系列(路由机制)

    参考文档: ug103-02-fundamentals-zigbee.pdf section4 zigbe routing concepts docs-05-3474-21-0csg-zigbee-s ...

  3. 人工智能AI芯片与Maker创意接轨(下)

    继「人工智能AI芯片与Maker创意接轨」的(上)篇中,认识了人工智能.深度学习,以及深度学习技术的应用,以及(中)篇对市面上AI芯片的类型及解决方案现况做了完整剖析后,系列文到了最后一篇,将带领各位 ...

  4. node安装和npm全局配置

    本文章环境 windows10 64位家庭版 Node10.15.3LTS 安装包下载 Node官网 安装node 点击安装文件, 一键安装, 注意安装位置和添加到环境变量(xx to PATH)选项 ...

  5. 防csrf详解

    CSRF概念:CSRF跨站点请求伪造(Cross—Site Request Forgery),跟XSS攻击一样,存在巨大的危害性,你可以这样来理解:       攻击者盗用了你的身份,以你的名义发送恶 ...

  6. 基于神念TGAM的脑波小车(2)

    将数据处理移植到STM32上,采用串口的DMA接收模式,注意的是DMA_MODE采用Circular,DMA_BufferSize>(8*512+36=4132)(小包8个字节,每秒512个,完 ...

  7. access和MySQL mssql

    Access.MSSQL.MYSQL数据库之间有什么区别?     Access数据库.MSSQL数据库.MYSQL数据库之间有什么区别?        不少企业和个人站长在网站制作时,会对数据库的概 ...

  8. MyBatis学习(一)————纯jdbc编程

    什么是JDBC  JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java ...

  9. python数据分析画图体验

    对于numpy的函数,pands等,不是很熟,我来copy一下code,敲击一下,找找感觉. 默认的导入包import numpy as npimport matplotlib.pyplot as p ...

  10. Daily Scrum7 11.11

    今日任务: 徐钧鸿:结束了SQL和Affairs的移植,修改了连接池,学习C#和java的正则表达式并且完成相关的移植 张艺:个人阅读作业 黄可嵩:完成高亮显示的移植,进一步移植搜索代码 徐方宇:继续 ...