Angular.js实现动态加载组件详解


Posted in Javascript onMay 28, 2017

前言

有时候需要根据URL来渲染不同组件,我所指的是在同一个URL地址中根据参数的变化显示不同的组件;这是利用Angular动态加载组件完成的,同时也会设法让这部分动态组件也支持AOT。

动态加载组件

下面以一个Step组件为示例,完成一个3个步骤的示例展示,并且可以通过URL user?step=step-one 的变化显示第N个步骤的内容。

1、resolveComponentFactory

首先,还是需要先创建动态加载组件模块。

import { Component, Input, ViewContainerRef, ComponentFactoryResolver, OnDestroy, ComponentRef } from '@angular/core';
@Component({
 selector: 'step',
 template: ``
})
export class Step implements OnDestroy {
 private currentComponent: ComponentRef<any>;

 constructor(private vcr: ViewContainerRef, private cfr: ComponentFactoryResolver) {}

 @Input() set data(data: { component: any, inputs?: { [key: string]: any } } ) {
  const compFactory = this.cfr.resolveComponentFactory(data.component);
  const component = this.vcr.createComponent(compFactory);
  if (data.inputs) {
  for (let key in data.inputs) {
   component.instance[key] = data.inputs[key];
  }
  }
  this.destroy();
  this.currentComponent = component;
 }

 destroy() {
 if (this.currentComponent) {
  this.currentComponent.destroy();
  this.currentComponent = null;
 }
 }

 ngOnDestroy(): void {
 this.destroy();
 }

}

抛开一销毁动作不谈的话,实际就两行代码:

let compFactory = this.cfr.resolveComponentFactory(this.comp);

利用 ComponentFactoryResolver 查找提供组件的 ComponentFactory,而后利用这个工厂来创建实际的组件。

this.compInstance = this.vcr.createComponent(compFactory);

这一切都非常简单。

而对于一些基本的参数,是直接对组件实例进行赋值。

for (let key in data.inputs) {
   component.instance[key] = data.inputs[key];
  }

最后,还需要告诉Angular AOT编译器为用户动态组件提供工厂注册,否则 ComponentFactoryResolver 会找不到它们,最简单就是利用 NgModule.entryComponents 进行注册。

@NgModule({
 entryComponents: [ UserOneComponent, UserTwoComponent, UserThirdComponent ]
})
export class AppModule { }

但这样其实还是挺奇怪的,entryComponents 本身可能还会存在其他组件。而动态加载组件本身是一个通用性非常强,因此,把它封装成名曰 StepModule 挺有必要的,这样的话,就可以创建一种看起来更舒服的方式。

@NgModule({
 declarations: [ Step ],
 exports: [ Step ]
})
export class StepModule {
 static withComponents(components: any) {
 return {
  ngModule: StepModule,
  providers: [
  { provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: components, multi: true }
  ]
 }
 }
}

通过利用 ANALYZE_FOR_ENTRY_COMPONENTS 将多个组件以更友好的方式动态注册至 entryComponents。

const COMPONENTS = [ ];

@NgModule({
 declarations: [ ...COMPONENTS ],
 imports: [
 StepModule.withComponents([ ...COMPONENTS ])
 ]
})
export class AppModule { }

2、一个示例

有3个Step步骤的组件,分别为:

// user-one.component.ts
import { Component, OnDestroy, Input, Injector, EventEmitter, Output } from '@angular/core';
@Component({
 selector: 'step-one',
 template: `<h2>Step One Component:params value: {{step}}</h2>`
})
export class UserOneComponent implements OnDestroy {
 private _step: string;
 @Input() 
 set step(str: string) {
 console.log('@Input step: ' + str);
 this._step = str;
 }
 get step() {
 return this._step;
 }

 ngOnInit() {
 console.log('step one init');
 }
 ngOnDestroy(): void {
 console.log('step one destroy');
 }

}

user-two、user-third 略同,这里组件还需要进行注册:

const STEPCOMPONENTS = [ UserOneComponent, UserTwoComponent, UserThirdComponent ];

@NgModule({
 declarations: [ ...STEPCOMPONENTS ],
 imports: [
 StepModule.withComponents([ ...STEPCOMPONENTS ])
 ]
})
export class AppModule { }

这里没有 entryComponents 字眼,而是为 StepModule 模块帮助我们动态注册。这样至少看起来更内聚一点,而且并不会与其他 entryComponents 在一起,待东西越多越不舒服。

最后,还需要 UserComponent 组件来维护步骤容器,会根据 URL 参数的变化,利用 StepComponent 组件动态加载相应组件。

@Component({
 selector: 'user',
 template: `<step [comp]="stepComp"></step>`
})
export class UserComponent {
 constructor(private route: ActivatedRoute) {}
 stepComp: any;
 ngOnInit() {
 this.route.queryParams.subscribe(params => {
  const step = params['step'] || 'step-one';
  // 组件与参数对应表
  const compMaps = {
  'step-one': { component: UserOneComponent, inputs: { step: step } },
  'step-two': { component: UserTwoComponent },
  'step-third': { component: UserThirdComponent },
  };
  this.stepComp = compMaps[step];
 });
 }
}

非常简单的使用,而且又对AOT比较友好。

总结

文章里面一直都在提AOT,其实AOT是Angular为了提供速度与包大小而生的,按我们项目的经验来看至少在包的大小可以减少到 40% 以上。

当然,如果你是用angular cli开发,那么,当你进行 ng build --prod 的时候,默认就已经开启 AOT 编译模式。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家三水点靠木的支持。

Javascript 相关文章推荐
javascript动画效果类封装代码
Aug 28 Javascript
javascript笔试题目附答案@20081025_jb51.net
Oct 26 Javascript
Javascript Global对象
Aug 13 Javascript
xmlhttp缓存清除的2种解决方法
Dec 13 Javascript
jquery批量设置属性readonly和disabled的方法
Jan 24 Javascript
禁用JavaScript控制台调试的方法
Mar 07 Javascript
JavaScript利用正则表达式替换字符串中的内容
Dec 12 Javascript
json数据处理及数据绑定
Jan 25 Javascript
js 作用域和变量详解
Feb 16 Javascript
详解如何使用Vue2做服务端渲染
Mar 29 Javascript
微信小程序模拟cookie的实现
Jun 20 Javascript
Json实现传值到后台代码实例
Jun 30 Javascript
利用node.js如何搭建一个简易的即时响应服务器
May 28 #Javascript
利用Angular.js编写公共提示模块的方法教程
May 28 #Javascript
Angular2入门教程之模块和组件详解
May 28 #Javascript
关于Angular2 + node接口调试的解决方案
May 28 #Javascript
对象不支持indexOf属性或方法的解决方法(必看)
May 28 #Javascript
设置cookie指定时间失效(实例代码)
May 28 #Javascript
Mac系统下Webstorm快捷键整理大全
May 28 #Javascript
You might like
可定制的PHP缩略图生成程式(需要GD库支持)
2007/03/06 PHP
浅谈php正则表达式中的非贪婪模式匹配的使用
2014/11/25 PHP
Yii模型操作之criteria查找数据库的方法
2016/07/15 PHP
完美解决php 导出excle的.csv格式的数据时乱码问题
2017/02/18 PHP
javascript中使用正则表达式清理table样式的代码
2020/04/01 Javascript
jQuery+PHP+MySQL二级联动下拉菜单实例讲解
2015/10/27 Javascript
AngularJs  E2E Testing 详解
2016/09/02 Javascript
12 款 JS 代码测试必备工具(翻译)
2016/12/13 Javascript
JS中使用正则表达式g模式和非g模式的区别
2017/04/01 Javascript
vue2.X组件学习心得(新手必看篇)
2017/07/05 Javascript
Vue不能观察到数组length的变化
2018/06/08 Javascript
GOJS+VUE实现流程图效果
2018/12/01 Javascript
微信小程序开发之左右分栏效果的实例代码
2019/05/20 Javascript
Node.js学习教程之Module模块
2019/09/03 Javascript
Vue快速实现通用表单验证的示例代码
2020/01/09 Javascript
javascript设计模式 ? 解释器模式原理与用法实例分析
2020/04/17 Javascript
Python内置数据类型详解
2014/08/18 Python
在Python的web框架中中编写日志列表的教程
2015/04/30 Python
浅析python继承与多重继承
2018/09/13 Python
远程部署工具Fabric详解(支持Python3)
2019/07/04 Python
把django中admin后台界面的英文修改为中文显示的方法
2019/07/26 Python
如何将PySpark导入Python的放实现(2种)
2020/04/26 Python
python学习之使用Matplotlib画实时的动态折线图的示例代码
2021/02/25 Python
总结30个CSS3选择器
2017/04/13 HTML / CSS
美国折扣网站:jClub
2017/08/07 全球购物
西班牙家用电器和电子产品购物网站:Mi Electro
2019/02/25 全球购物
澳大利亚珠宝商:Shiels
2019/10/06 全球购物
计算机应用与科学个人的自我评价
2013/11/15 职场文书
同学会邀请书大全
2014/01/12 职场文书
班主任班级寄语大全
2014/04/04 职场文书
设计专业毕业生求职信
2014/06/25 职场文书
我的中国梦演讲稿600字
2014/08/19 职场文书
煤矿安全协议书
2014/08/20 职场文书
助学金感谢信
2015/01/20 职场文书
装配车间主任岗位职责
2015/04/08 职场文书
详细介绍Java中的CyclicBarrier
2022/04/13 Java/Android