ionic 之 Dynamic Component Loader

产品需求: 根据服务器返回的配置文件, 动态的调用组件生成页面

上面的需求乍一听,很简单! 在React.js里面, 可以使用Jsx语法,分分钟搞定. 或者可以使用innerHTML动态的嵌入组件.

然而, 在angualr中, 没有Jsx语法, innerHTML只能嵌入html标签;
如果嵌入组件的话, 组件中的js就失效了(I think it’s best to pretend innerHTML doesn’t exist.)

那么在angular中具体怎么实现上述的需求呢? 官网给出了一个demo 点我;
具体可以参照官网

当然官网的例子是angular写的, 可以翻译成ionic形式; 具体的可以查看底部的demo

ionic 容器动态加载组件

1.1 自定义组件 根据需求定义需要的组件


ionic 之 Dynamic Component Loader_第1张图片
自定义组件

1.2 在添加组件之前,先要定义一个锚点来告诉Angular要把组件插入到什么地方。
定义一个名叫container的辅助指令来在模板中标记出有效的插入点。

ionic 之 Dynamic Component Loader_第2张图片
创建container指令

指令代码如下:

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

@Directive({
  selector: '[ll-container]' // Attribute selector
})
export class ContainerDirective {

  constructor(public viewContainerRef: ViewContainerRef) {
  }

}

1.3 在1.1图片中的ll-container是一个组件容器, 想要实现动态加载的组件, 都需放在该容器里面

ll-container容器中需要创建一个模板,并添加指令ll-container


ll-container.ts中具体实现:
LlContainerComponent接收一个AdItem对象的数组作为输入,它最终来自ContainerProviderAdItem对象指定要加载的组件类,以及绑定到该组件上的任意数据。

import { Component, Input, AfterViewInit, ViewChild, ComponentFactoryResolver, OnDestroy } from '@angular/core';
import {AdItem} from "../../common/adItem";
import {ContainerDirective} from "../../directives/container/container";
import {LlTmpComponent} from "../ll-tmp/ll-tmp";

@Component({
  selector: 'll-container',
  templateUrl: 'll-container.html'
})
export class LlContainerComponent {

  @Input() containerDirec:string;

  @Input() item;
  @ViewChild(ContainerDirective) adHost: ContainerDirective;
  subscription: any;
  interval: any;

  constructor(private componentFactoryResolver: ComponentFactoryResolver) { }

  ngAfterViewInit() {

    this.loadComponent();
  }

  loadComponent() {

    let adItem = this.item;

    let componentFactory = this.componentFactoryResolver.resolveComponentFactory(adItem.component);

    let viewContainerRef = this.adHost.viewContainerRef;
    viewContainerRef.clear();

    let componentRef = viewContainerRef.createComponent(componentFactory);
    (componentRef.instance).data = adItem.data;
  }
}

  1. 模拟服务器配置文件
public configs = [
    {
      id: "1111",
      categoryId:"a1",
      dataSource: this.mock.sliderArray,
      name: "广告"
    },
    {
      id: "2222",
      categoryId:"a2",
      dataSource: this.mock.noticeList,
      name: "noticeList"
    },
    {
      id: "3333",
      categoryId:"a3",
      dataSource: this.mock.hotMenu1,
      name: "hotmenus1"
    },
    {
      id: "4444",
      categoryId:"a4",
      dataSource: this.mock.menuList,
      name: "menus"
    },
    {
      id: "5555",
      categoryId:"a3",
      dataSource: this.mock.hotMenu2,
      name: "hotmenus2"
    },
    {
      id: "6666",
      categoryId:"a5",
      dataSource: this.mock.activityList,
      name: "活动列表"
    }
  ];
  1. 根据配置文件动态的调用组件
  /**
   * 获取AdItem对象的数组
   * 
   * @returns 
   * @memberof ContainerProvider
   */
  getItemArray() {

    let configArray = this.appConfig.configs;
    let tempComponent;

    for (let i = 0; i < configArray.length; i++) {
      let item = configArray[i];
      tempComponent = this.getComponent(item.categoryId);
      this.dataSource.push(new AdItem(tempComponent, {dataSource: item.dataSource}));
    }
    return this.dataSource;
  }

  /**
   * 根据 categoryId 返回不同的组件
   * 
   * @param categoryId 
   */
  getComponent(categoryId) {

    if(!categoryId){
      return '';
    }
    if (categoryId == "a1") {
      return LlSliderComponent;
    } else if (categoryId == "a2") {
      return LlNoticeSliderComponent;
    } else if (categoryId == "a3") {
      return LlHotMenuWrapperComponent;
    } else if (categoryId == "a4") {
      return LlMenuWrapperComponent;
    } else if (categoryId == "a5") {
      return LlHomeListWrapperComponent;
    }
  }
  1. 在需要动态显示的界面调用容器


  
  1. 实现效果


    ionic 之 Dynamic Component Loader_第3张图片
    效果图

源码由于文件比较大, 上传到了百度云, 链接:https://pan.baidu.com/s/1htC5aAg 密码:qgp8

你可能感兴趣的:(ionic 之 Dynamic Component Loader)