美文网首页
ionic4/angular6 slides组件动态加载组件

ionic4/angular6 slides组件动态加载组件

作者: Gemkey | 来源:发表于2018-10-27 12:19 被阅读439次

    在开发过程中,遇到需要使用ionSlides来动态加载数据的一个需求,即在每次切换到新的slide时,需要动态的去加载每个组件的数据。在刚开始做开发的时候发现直接使用组件时,所有组件都会被加载,然后就去请求后台,切换slide时,再去请求,这就导致了大量的资源浪费,也增加了后台的压力,尤其是当请求比较缓慢时体验是非常差的,因此便考虑需要怎么处理这个问题。

    首先想到的是做组件的动态加载,于是就跟着官网的示例开发自己的功能,官网链接:https://www.angular.cn/guide/dynamic-component-loader。在这里就以demo来做演示。
    首先创建一个dynamic-component模块,目录结构如下:

    目录结构

    其中
    1.lnk-image组件为需要被动态加载的组件
    2.anchor为锚点指令

    dynamic-component.module.ts

    import {NgModule} from '@angular/core';
    import {CommonModule} from '@angular/common';
    import {FormsModule} from '@angular/forms';
    import {RouterModule, Routes} from '@angular/router';
    
    import {IonicModule} from '@ionic/angular';
    
    import {DynamicComponentPage} from './dynamic-component.page';
    import {AnchorDirective} from './directive/anchor/anchor.directive';
    import {LnkImageComponent} from './component/image/lnk-image.component';
    
    const routes: Routes = [
        {
            path: '',
            component: DynamicComponentPage
        }
    ];
    
    @NgModule({
        imports: [
            CommonModule,
            FormsModule,
            IonicModule,
            RouterModule.forChild(routes)
        ],
        declarations: [
            DynamicComponentPage,
            AnchorDirective,
            LnkImageComponent
        ],
        entryComponents: [
            LnkImageComponent
        ]
    })
    export class DynamicComponentPageModule {
    }
    

    dynamic-component.page.html

    <ion-header>
      <ion-toolbar>
        <ion-buttons slot="start">
          <ion-menu-button></ion-menu-button>
        </ion-buttons>
        <ion-title>动态组件</ion-title>
      </ion-toolbar>
    </ion-header>
    
    <ion-content padding>
      <ion-slides pager (ionSlidesDidLoad)="onSlidesDidLoad($event)" (ionSlideDidChange)="onSlideDidChange($event)">
        <ion-slide *ngFor="let image of images">
          <ng-template appAnchor></ng-template>
        </ion-slide>
      </ion-slides>
    </ion-content>
    
    import {Component, ComponentFactoryResolver, OnInit, QueryList, Type, ViewChild, ViewChildren} from '@angular/core';
    import {LnkImageComponent} from './component/image/lnk-image.component';
    import {Slides} from '@ionic/angular';
    import {AnchorDirective} from './directive/anchor/anchor.directive';
    
    @Component({
        selector: 'app-dynamic-component',
        templateUrl: './dynamic-component.page.html',
        styleUrls: ['./dynamic-component.page.scss'],
    })
    export class DynamicComponentPage implements OnInit {
        images = [                                                              // 图片组件
            {src: 'http://t2.hddhhn.com/uploads/tu/20150520/061112158440.jpg', author: 'gemini'},
            {src: 'http://img.zcool.cn/community/0125fd5770dfa50000018c1b486f15.jpg@1280w_1l_2o_100sh.jpg', author: 'naci'},
            {src: 'http://t2.hddhhn.com/uploads/tu/20150520/152219311390.jpg', author: 'lucy'},
            {src: 'http://img12.3lian.com/gaoqing02/01/58/85.jpg', author: 'grey'},
            {src: 'http://t2.hddhhn.com/uploads/tu/20150520/061109468190.jpg', author: 'elusa'}
        ];
        currentIndex;                                                           // 当前slide的索引
        components: DynamicComponentItem[];                                     // 动态组件数组
        @ViewChild(Slides) slides: Slides;                                      // slides 对象
        @ViewChildren(AnchorDirective) anchors: QueryList<AnchorDirective>;     // 锚点对象
    
        constructor(
            private componentFactoryResolver: ComponentFactoryResolver
        ) {
        }
    
        ngOnInit() {
            // 初始化组件参数
            this.initComponents();
        }
    
        /**
         * slides 对象初始化完成事件
         * @author : gemini
         * @date: 2018/10/27
         * @param $event 事件对象
         */
        onSlidesDidLoad($event) {
            this.loadComponent();
        }
    
        /**
         * slides 对象切换完成
         * @author : gemini
         * @date: 2018/10/27
         * @param $event 事件对象
         */
        onSlideDidChange($event) {
            this.loadComponent();
        }
    
        /**
         * 加载组件
         * @author : gemini
         * @date: 2018/10/27
         */
        async loadComponent() {
            this.currentIndex = await this.slides.getActiveIndex();
            // 根据当前slide的索引,拿到当前动态组件对象item
            const dynamicComponentItem = this.components[this.currentIndex];
            // 根据当前slide的索引,从锚点列表中,取到对应的slide上的锚点
            const anchor = this.anchors.toArray()[this.currentIndex];
            // 获取组件工厂
            const componentFactory = this.componentFactoryResolver.resolveComponentFactory(LnkImageComponent);
            // 获取锚点上的ViewContainerRef
            const viewContainerRef = anchor.viewContainerRef;
            // 清除原模板上的内容
            viewContainerRef.clear();
            // 动态创建组件
            const componentRef = viewContainerRef.createComponent(componentFactory);
            // 给组件传入数据
            (<LnkImageComponent>componentRef.instance).src = dynamicComponentItem.data.src;
            (<LnkImageComponent>componentRef.instance).author = dynamicComponentItem.data.author;
        }
    
        /**
         * 初始化组件数组
         * @author : gemini
         * @date: 2018/10/27
         */
        initComponents() {
            this.components = [];
            // 根据参数,创建动态组件对象
            for (let i = 0; i < this.images.length; i++) {
                const image = this.images[I];
                this.components.push(new DynamicComponentItem(LnkImageComponent, {src: image.src, author: image.author}));
            }
        }
    }
    
    /**
     * 动态组件对象
     * @author : gemini
     * @date: 2018/10/27
     */
    export class DynamicComponentItem {
        /**
         * 构造函数中的两个参数
         * @author : gemini
         * @date: 2018/10/27
         * @param component 组件对象
         * @param data 需要传入给组件的数据
         */
        constructor(public component: Type<any>, public data: any) {
        }
    }
    

    anchor.directive.ts

    import {Directive, ViewContainerRef} from '@angular/core';
    
    /**
     * 锚点指令
     * @author : gemini
     * @date: 2018/10/27
     */
    @Directive({
        selector: '[appAnchor]'
    })
    export class AnchorDirective {
    
        constructor(public viewContainerRef: ViewContainerRef) {
        }
    
    }
    

    lnk-image.component.ts

    import {Component, Input, OnInit} from '@angular/core';
    
    @Component({
        selector: 'app-lnk-image',
        templateUrl: './lnk-image.component.html',
        styleUrls: ['./lnk-image.component.scss']
    })
    export class LnkImageComponent implements OnInit {
        @Input() src;         // 图片显示的url
        @Input() author;      // 作者
        constructor() {
        }
    
        ngOnInit() {
            console.log('ImageComponent', `[author]:${this.author};[src]${this.src};`);
        }
    }
    
    <div>
        <div class="image-container">
            <img [src]="src">
        </div>
        <div class="author">
            <h5>{{author}}</h5>
        </div>
    </div>
    
    .image-container {
      width: 100%;
      height: 50%;
      img {
        width: 100%;
        height: 100%;
      }
    }
    
    .author {
      text-align: center;
    }
    

    在自己的项目中需要使用时,只需要作出如下替换:
    1.images可以通过http请求,或在service以及作为组件入参等各种方式传入,然后再做初始化组件对象。
    2.替换对应的需要动态加载的组件。

    效果

    从图片中可以看到,每次切换图片后,才会去请求图片的url。

    相关文章

      网友评论

          本文标题:ionic4/angular6 slides组件动态加载组件

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