美文网首页我爱编程
ionic 之 Dynamic Component Loader

ionic 之 Dynamic Component Loader

作者: 壹点微尘 | 来源:发表于2018-01-23 11:14 被阅读245次
    产品需求: 根据服务器返回的配置文件, 动态的调用组件生成页面

    上面的需求乍一听,很简单! 在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 自定义组件 根据需求定义需要的组件


    自定义组件

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

    创建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

    <ng-template ll-container></ng-template>
    

    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);
        (<LlTmpComponent>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. 在需要动态显示的界面调用容器
    <ion-content>
    
      <div *ngIf="itemArray.length !=0" >
        <ll-container *ngFor="let item of itemArray;" [item]="item"></ll-container>
      </div >
    
    </ion-content>
    
    1. 实现效果


      效果图

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

    相关文章

      网友评论

        本文标题:ionic 之 Dynamic Component Loader

        本文链接:https://www.haomeiwen.com/subject/onajaxtx.html