Angular 动态组件
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 动态组件的更多相关文章
- Angular动态组件
		
一.主页面: app.component.html: <button (click)="load();">动态</button> 2<div #dom ...
 - angular 动态组件类型
		
出处:https://github.com/Penggggg/angular-component-practices 组件类型1:纯函数功能,而没有视图部分,即Factory(类似于$http) pr ...
 - Angular 学习笔记 (动态组件 & Material Overlay & Dialog 分析)
		
更新: 2019-11-24 dialog vs router link refer : https://stackoverflow.com/questions/51821766/angular-m ...
 - Angular动态创建组件之Portals
		
这篇文章主要介绍使用Angular api 和 CDK Portals两种方式实现动态创建组件,另外还会讲一些跟它相关的知识点,如:Angular多级依赖注入.ViewContainerRef,Por ...
 - angular2 学习笔记 ( Dynamic Component 动态组件)
		
更新 2018-02-07 详细讲一下 TemplateRef 和 ViewContainerRef 的插入 refer : https://segmentfault.com/a/1190000008 ...
 - vuejs动态组件给子组件传递数据
		
vuejs动态组件给子组件传递数据 通过子组件定义时候的props可以支持父组件给子组件传递数据,这些定义的props在子组件的标签中使用绑定属性即可,但是如果使用的是<component> ...
 - C++ 类的动态组件化技术
		
序言: N年前,我们曾在软件开发上出现了这样的困惑,用VC开发COM组件过于复杂,用VB开发COM组件发现效率低,而且不能实现面向对象的很多特性,例如,继承,多态等.更况且如何快速封装利用历史遗留的大 ...
 - Hibernate学习---第五节:普通组件和动态组件
		
一.普通组件映射配置 1.创建组件类,代码如下: package learn.hibernate.bean; /** * 组件类 */ public class Phones { private St ...
 - vue2入坑随记(二) -- 自定义动态组件
		
学习了Vue全家桶和一些UI基本够用了,但是用元素的方式使用组件还是不够灵活,比如我们需要通过js代码直接调用组件,而不是每次在页面上通过属性去控制组件的表现.下面讲一下如何定义动态组件. Vue.e ...
 
随机推荐
- pycharm字体放大缩小设置
			
放大设置 File —> settings—> Keymap —>在搜寻框中输入:increase —> Increase Font Size(双击) —> 在弹出的对话 ...
 - 【ASP.NET Core】运行原理(2):启动WebHost
			
本系列将分析ASP.NET Core运行原理 [ASP.NET Core]运行原理[1]:创建WebHost [ASP.NET Core]运行原理[2]:启动WebHost [ASP.NET Core ...
 - 【轮子狂魔】WeChatAPI 开源系统架构详解
			
如果使用WeChatAPI,它扮演着什么样的角色? 从图中我们可以看到主要分为3个部分: 1.业务系统 2.WeChatAPI: WeChatWebAPI,主要是接收微信服务器请求: WeChatAP ...
 - Flink HA
			
standalone 模式的高可用 部署 flink 使用zookeeper协调多个运行的jobmanager,所以要启用flink HA 你需要把高可用模式设置成zookeeper,配置zookee ...
 - VisionPro相机操作类
			
在网站上看到这个,保存下来,以后用到了,再看一下.谢谢原创的分享! #region 获得相机信息方法 /// <summary> /// 公有静态方法,查找单个相机.例如“Basler” ...
 - Metasploit拿Shell
			
进入metasploit系统 msfconsole Nmap端口扫描 nmap –sV IP(或者域名),如果机器设置有防火墙禁ping,可以使用nmap -P0(或者-Pn) –sV IP(或者域名 ...
 - 备份win10的驱动程序
			
目录 折腾历程 怎么备份驱动 备份的驱动如何使用 关于驱动程序的OS兼容性 驱动程序的其他安装方式 1.折腾历程 从闲鱼上收了一个INSIGNIA的二合一笔记本,w7100,因原装win10性能不行自 ...
 - ansible软件2
			
常用软件安装及使用目录 ansible使用1 第1章 copy模块 1.1 创建文件及写入内容 1. [root@m01 scripts]# ansible oldboy -m copy -a &q ...
 - maven实战读书笔记(二)
			
一个Spring加载属性的工具类,指定目标位置之后可以用${}的方式加载配置文件 测试maven工程发送email的例子:运行成功的例子—github 常用的命令: mvn clean compile ...
 - Scrum立会报告+燃尽图(十二月五日总第三十六次):Final阶段分配任务
			
此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2284 项目地址:https://git.coding.net/zhang ...