ionic4/angular6 slides组件动态加载组件
2018-10-27 本文已影响439人
Gemkey
在开发过程中,遇到需要使用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。