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 相关文章推荐
限制复选框的最大可选数
Jul 01 Javascript
js封装的textarea操作方法集合(兼容很好)
Nov 16 Javascript
基于jquery的无刷新分页技术
Jun 11 Javascript
推荐10个超棒的jQuery工具提示插件
Oct 11 Javascript
JQGrid的用法解析(列编辑,添加行,删除行)
Nov 08 Javascript
JavaScript中for-in遍历方式示例介绍
Feb 11 Javascript
使用AngularJS制作一个简单的RSS阅读器的教程
Jun 18 Javascript
javascript学习指南之回调问题
Apr 23 Javascript
各式各样的导航条效果css3结合jquery代码实现
Sep 17 Javascript
基于jQuery实现中英文切换导航条效果
Sep 18 Javascript
微信小程序实现文字跑马灯效果
May 26 Javascript
webpack 静态资源集中输出的方法示例
Nov 09 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
在普通HTTP上安全地传输密码
2007/07/21 PHP
php 图片上传类代码
2009/07/17 PHP
php set_magic_quotes_runtime() 函数过时解决方法
2010/07/08 PHP
php微信开发之批量生成带参数的二维码
2016/06/26 PHP
Yii框架实现记录日志到自定义文件的方法
2017/05/23 PHP
PHP调用其他文件中的类
2018/04/02 PHP
Yii框架页面渲染操作实例详解
2019/07/19 PHP
Laravel框架中集成MongoDB和使用详解
2019/10/17 PHP
php设计模式之建造器模式分析【星际争霸游戏案例】
2020/01/23 PHP
解析JavaScript中的标签语句
2013/06/19 Javascript
jqGrid增加时--判断开始日期与结束日期(实例解析)
2013/11/08 Javascript
setTimeout自动触发一个js的方法
2014/01/15 Javascript
《JavaScript DOM 编程艺术》读书笔记之JavaScript 图片库
2015/01/09 Javascript
jQuery原生的动画效果
2015/07/10 Javascript
jQuery地图map悬停显示省市代码分享
2015/08/20 Javascript
基于Node.js的强大爬虫 能直接发布抓取的文章哦
2016/01/10 Javascript
JavaScript获取当前运行脚本文件所在目录的方法
2016/02/03 Javascript
Angularjs 设置全局变量的方法总结
2016/10/20 Javascript
微信小程序学习(4)-系统配置app.json详解
2017/01/12 Javascript
JavaScript引用类型Date常见用法实例分析
2018/08/08 Javascript
原生jQuery实现只显示年份下拉框
2020/12/24 jQuery
python脚本实现数据导出excel格式的简单方法(推荐)
2016/12/30 Python
Python 加密的实例详解
2017/10/09 Python
基于Python实现的微信好友数据分析
2018/02/26 Python
详解Python 解压缩文件
2019/04/09 Python
Django 配置多站点多域名的实现步骤
2019/05/17 Python
Python如何计算语句执行时间
2019/11/22 Python
Python本地及虚拟解释器配置过程解析
2020/10/13 Python
pytorch 移动端部署之helloworld的使用
2020/10/30 Python
利用CSS的Sass预处理器(框架)来制作居中效果
2016/03/10 HTML / CSS
HTML5 预加载让页面得以快速呈现
2013/08/13 HTML / CSS
详解HTML5中CSS外观属性
2020/09/10 HTML / CSS
四风问题个人自查剖析材料思想汇报
2014/09/21 职场文书
导师鉴定意见
2015/06/05 职场文书
初中开学典礼新闻稿
2015/07/17 职场文书
2016入党培训心得体会范文
2016/01/08 职场文书