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 相关文章推荐
来自chinaz的ajax获取评论代码
May 03 Javascript
js可突破windows弹退效果代码
Aug 09 Javascript
侧栏跟随滚动的简单实现代码
Mar 18 Javascript
页面js遇到乱码问题的解决方法是和无法转码的情况
Apr 30 Javascript
IE下通过a实现location.href 获取referer的值
Sep 04 Javascript
JQuery EasyUI Layout 在from布局自适应窗口大小的实现方法
May 28 Javascript
js中遍历对象的属性和值的方法
Jul 27 Javascript
js转html实体的方法
Sep 27 Javascript
angularJs关于指令的一些冷门属性详解
Oct 24 Javascript
微信小程序实现缓存根据不同的id来进行设置和读取缓存
Jun 12 Javascript
vue+elementui 对话框取消 表单验证重置示例
Oct 29 Javascript
vue组件暴露和.js文件暴露接口操作
Aug 11 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使用pcntl_fork实现多进程下载图片的方法
2014/12/16 PHP
PHP中开启gzip压缩的2种方法
2015/01/31 PHP
浅析PHP中call user func()函数及如何使用call user func调用自定义函数
2015/11/05 PHP
php5.x禁用eval的操作方法
2018/10/19 PHP
在textarea中显示html页面的javascript代码
2007/04/20 Javascript
jquery last-child 列表最后一项的样式
2010/01/22 Javascript
一些实用的jQuery代码片段收集
2011/07/12 Javascript
node.js中的Socket.IO使用实例
2014/11/04 Javascript
JavaScript原生对象之String对象的属性和方法详解
2015/03/13 Javascript
javascript实现表格增删改操作实例详解
2015/05/15 Javascript
简述AngularJS的控制器的使用
2015/06/16 Javascript
jQuery zTree加载树形菜单功能
2016/02/25 Javascript
js编写当天简单日历效果【实现代码】
2016/05/03 Javascript
详解使用nodeJs安装Vue-cli
2017/05/17 NodeJs
vue集成百度UEditor富文本编辑器使用教程
2018/09/21 Javascript
微信小程序实现简单评论功能
2018/11/28 Javascript
在JavaScript中实现链式调用的实现
2019/12/24 Javascript
js实现头像上传并且可预览提交
2020/12/25 Javascript
vue3+typeScript穿梭框的实现示例
2020/12/29 Vue.js
Python时间戳与时间字符串互相转换实例代码
2013/11/28 Python
Python利用heapq实现一个优先级队列的方法
2019/02/03 Python
pyenv与virtualenv安装实现python多版本多项目管理
2019/08/17 Python
pycharm设置python文件模板信息过程图解
2020/03/10 Python
Python爬虫获取页面所有URL链接过程详解
2020/06/04 Python
Python实现石头剪刀布游戏
2021/01/20 Python
英国殿堂级有机护肤品牌:Rodial
2017/04/17 全球购物
法国在线宠物店:zooplus.fr
2018/02/23 全球购物
英国川宁茶官方网站:Twinings茶
2019/05/21 全球购物
JDO的含义
2012/11/17 面试题
学生安全教育材料
2014/02/14 职场文书
工程专业应届生求职信
2014/02/19 职场文书
审计专业自荐信范文
2014/04/21 职场文书
英语三分钟演讲稿
2014/08/19 职场文书
个人授权委托书
2014/09/15 职场文书
个人自我鉴定怎么写?
2019/07/01 职场文书
python实现简单的聊天小程序
2021/07/07 Python