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 相关文章推荐
在IE和VB中支持png图片透明效果的实现方法(vb源码打包)
Apr 01 Javascript
基于jQuery选择器的整理集合
Apr 26 Javascript
深入理解JavaScript系列(38):设计模式之职责链模式详解
Mar 04 Javascript
第九篇Bootstrap导航菜单创建步骤详解
Jun 21 Javascript
javascript简单实现等比例缩小图片的方法
Jul 27 Javascript
js 毫秒转天时分秒的实例
Nov 17 Javascript
vue.js实现只弹一次弹框
Jan 29 Javascript
解决vue中使用Axios调用接口时出现的ie数据处理问题
Aug 13 Javascript
vue的for循环使用方法
Feb 12 Javascript
vue封装swiper代码实例解析
Oct 08 Javascript
Vue封装Axios请求和拦截器的步骤
Sep 16 Javascript
在vue中获取wangeditor的html和text的操作
Oct 23 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使用内置函数生成图片的方法详解
2016/05/09 PHP
分享精心挑选的12款优秀jQuery Ajax分页插件和教程
2012/08/09 Javascript
『jQuery』名称冲突使用noConflict方法解决
2013/04/22 Javascript
在每个匹配元素的外部插入新元素的方法
2013/12/20 Javascript
一个JavaScript函数把URL参数解析成Json对象
2014/09/24 Javascript
js实现仿Windows风格选项卡和按钮效果实例
2015/05/13 Javascript
javascript简单比较日期大小的方法
2016/01/05 Javascript
JS使用单链表统计英语单词出现次数
2016/06/16 Javascript
jQuery实现点击弹出背景变暗遮罩效果实例代码
2016/06/24 Javascript
Javascript中的prototype与继承
2017/02/06 Javascript
Angular 4.x 路由快速入门学习
2017/05/03 Javascript
解决layui弹框失效的问题
2019/09/09 Javascript
[01:19:35]DOTA2上海特级锦标赛主赛事日 - 3 败者组第三轮#2Fnatic VS OG第二局
2016/03/05 DOTA
详解Python中的from..import绝对导入语句
2016/06/21 Python
Python实现时钟显示效果思路详解
2018/04/11 Python
Python解决走迷宫问题算法示例
2018/07/27 Python
pytorch 输出中间层特征的实例
2019/08/17 Python
python连接PostgreSQL数据库的过程详解
2019/09/18 Python
python常见字符串处理函数与用法汇总
2019/10/30 Python
css3 线性渐变和径向渐变示例附图
2014/04/08 HTML / CSS
将SVG图引入到HTML页面的实现
2019/09/20 HTML / CSS
美国Rue La La闪购网站:奢侈品、中高档品牌限时折扣
2016/10/19 全球购物
英国团购网站:Groupon英国
2017/11/28 全球购物
Chantelle仙黛尔内衣美国官网:法国第一品牌内衣
2018/07/26 全球购物
香港网上花店:FlowerAdvisor香港
2019/05/30 全球购物
什么是属性访问器
2015/10/26 面试题
报考公务员诚信承诺书
2014/08/29 职场文书
软件测试专业推荐信
2014/09/18 职场文书
药店采购员岗位职责
2014/09/30 职场文书
2014年纳税评估工作总结
2014/12/23 职场文书
家长通知书家长意见
2014/12/30 职场文书
社区党风廉政建设调研报告
2015/01/01 职场文书
运动会入场词
2015/07/18 职场文书
2015初中教导处工作总结
2015/07/21 职场文书
详解CocosCreator项目结构机制
2021/04/14 Javascript
Sql Server之数据类型详解
2022/02/28 SQL Server