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

原文地址:https://www.cnblogs.com/zhangfengyang/p/8432493.html

时间: 2024-07-29 00:29:16

Angular 动态组件的相关文章

Angular动态创建组件之Portals

这篇文章主要介绍使用Angular api 和 CDK Portals两种方式实现动态创建组件,另外还会讲一些跟它相关的知识点,如:Angular多级依赖注入.ViewContainerRef,Portals可以翻译为 门户 ,我觉得放到这里叫 入口 更好,可以理解为动态创建组件的入口,类似于小程序或者Vue中的Slot. cdk全名Component Development Kit 组件开发包,是Angular官方在开发基于Material Design的组件库时抽象出来单独的一个开发包,里面

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

一样这一篇最要讲概念而已. refer : http://blog.rangle.io/dynamically-creating-components-with-angular-2/ (例子)https://www.ag-grid.com/ag-grid-angular-aot-dynamic-components/ (动态 entryComponents) http://stackoverflow.com/questions/40106480/what-are-projectable-node

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

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

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

学习了Vue全家桶和一些UI基本够用了,但是用元素的方式使用组件还是不够灵活,比如我们需要通过js代码直接调用组件,而不是每次在页面上通过属性去控制组件的表现.下面讲一下如何定义动态组件. Vue.extend 思路就是拿到组件的构造函数,这样我们就可以new了.而Vue.extend可以做到:https://cn.vuejs.org/v2/api/#Vue-extend // 创建构造器 var Profile = Vue.extend({ template: '<p>{{firstName

Vue动态组件

前面的话 让多个组件使用同一个挂载点,并动态切换,这就是动态组件.本文将详细介绍Vue动态组件 概述 通过使用保留的 <component> 元素,动态地绑定到它的 is 特性,可以实现动态组件 <div id="example"> <button @click="change">切换页面</button> <component :is="currentView"></compon

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

序言: N年前,我们曾在软件开发上出现了这样的困惑,用VC开发COM组件过于复杂,用VB开发COM组件发现效率低,而且不能实现面向对象的很多特性,例如,继承,多态等.更况且如何快速封装利用历史遗留的大量C++代码本身就是一个大的难题. 当时,开发小组的成员通过共同努力,摸索了一套C++类的动态组件化技术,很好的解决了以上的问题,通过这个技术,我们继承了大量的C++代码,同时使这些C++程序以COM+组件的形式得以新生.通过这几年在实际应用中的考验,这个技术是成熟可靠的. 也许新的系统大多数都完全

动态组件(选项卡):

本文是基于vue-cli脚手架基础上对动态组件做简单介绍,关于脚手架的介绍,请见:vue脚手架的安装流程(vue-cli). 在src文件夹下创建components文件夹,并在其下创建Aaa.vue和Bbb.vue两个组件文件,如下图: 再在App.vue中做如下的一些配置,即可完成有组件实现的选项卡切换: 效果图如下:

获取iframe(angular 动态页面)高度

问题比较特殊,google了好久才得到启示 开发的angular页面,需要嵌入到客户的web页中,以iframe方式.由于iframe的高度需要指定,而angular动态生成机制导致页面高度会随时变化, 就会出现2个滚动条,一个是页面本身,一个是iframe里的. 解决方法如下: 1.写一个directive监听angular的$digest,实时获取body高度,通过 HTML5 postMessage方式传出 在HTML5中新增了postMessage方法,postMessage可以实现跨文

vue教程3-03 vue组件,定义全局、局部组件,配合模板,动态组件

一.定义一个组件 定义一个组件: 1. 全局组件 var Aaa=Vue.extend({ template:'<h3>我是标题3</h3>' }); Vue.component('aaa',Aaa); *组件里面放数据: data必须是函数的形式,函数必须返回一个对象(json) 2. 局部组件 放到某个组件内部 var vm=new Vue({ el:'#box', data:{ bSign:true }, components:{ //局部组件 aaa:Aaa } }); 1