angular中支持可以通过路由来懒加载某些页面模块已达到减少首屏尺寸, 提高首屏加载速度的目的. 但是这种通过路由的方式有时候是无法满足需求的。【相关教程推荐:《angularjs视频教程》】
(资料图片仅供参考)
比如, 点击一个按钮后显示一行工具栏, 这个工具栏组件我不希望它默认打包进main.js
, 而是用户点按钮后动态把组件加载并显示出来.
那为什么要动态加载呢? 如果直接在目标页面组件引入工具栏组件, 那么工具栏组件中的代码就会被打包进目标页面组件所在的模块, 这会导致目标页面组件所在的模块生成的js体积变大; 通过动态懒加载的方式, 可以让工具栏组件只在用户点了按钮后再加载, 这样就可以达到减少首屏尺寸的目的.
为了演示, 新建一个angular项目, 然后再新建一个ToolbarModule
, 项目的目录结构如图
为了达到演示的目的, 我在ToolbarModule
的html模板中放了个将近1m的base64图片, 然后直接在AppModule
中引用ToolbarModule
, 然后执行ng build
, 执行结果如图
可以看到打包尺寸到达了1.42mb
, 也就是说用户每次刷新这个页面, 不管用户有没有点击显示工具栏按钮, 工具栏组件相关的内容都会被加载出来, 这造成了资源的浪费, 所以下面将ToolbarModule
从AppModule
的imports
声明中移除, 然后在用户点击首次点击显示时懒加载工具栏组件.
懒加载工具栏组件
首先, 新建一个ToolbarModule
和ToolbarComponent
, 并在ToolbarModule
声明ToolbarComponent
toolbar.module.ts
import { NgModule } from "@angular/core";import { CommonModule } from "@angular/common";import { ToolbarComponent } from "./toolbar.component"; @NgModule({ declarations: [ToolbarComponent], imports: [CommonModule], exports: [ToolbarComponent],})class ToolbarModule {} export { ToolbarComponent, ToolbarModule };
登录后复制
toolbar.component.ts
import { Component, OnInit } from "@angular/core";@Component({ selector: "toolbar", templateUrl: "./toolbar.component.html", styles: [ ` svg { width: 64px; height: 64px; } img { width: 64px; height: 64px; object-fit: cover; } `, ],})export class ToolbarComponent implements OnInit { constructor() {} ngOnInit(): void {}}
登录后复制
toolbar.component.html
登录后复制
然后再AppComponent
的中按钮点击事件处理程序中写加载工具栏模块的代码:
app.component.ts
import { Component, createNgModuleRef, Injector, ViewChild, ViewContainerRef } from "@angular/core";@Component({ selector: "root", template: `
首屏内容
`,})export class AppComponent { title = "ngx-lazy-load-demo"; toolbarLoaded = false; isToolbarVisible = false; @ViewChild("toolbar", { read: ViewContainerRef }) toolbarViewRef!: ViewContainerRef; constructor(private _injector: Injector) {} toggleToolbarVisibility() { this.isToolbarVisible = !this.isToolbarVisible; this.loadToolbarModule().then(); } private async loadToolbarModule() { if (this.toolbarLoaded) return; this.toolbarLoaded = true; const { ToolbarModule, ToolbarComponent } = await import("./toolbar/toolbar.module"); const moduleRef = createNgModuleRef(ToolbarModule, this._injector); const { injector } = moduleRef; const componentRef = this.toolbarViewRef.createComponent(ToolbarComponent, { injector, ngModuleRef: moduleRef, }); }}
登录后复制
关键在于其中的第32-42行, 首先通过一个动态import
导入toolbar.module.ts
中的模块, 然后调用createNgModuleRef
并传入当前组件的Injector
作为ToolbarModule
的父级Injector
, 这样就实例化了ToolbarModule
得到了moduleRef
对象, 最后就是调用html模板中声明的
的ViewContainerRef
对象的createComponent
方法创建ToolbarComponent
组件
private async loadToolbarModule() { if (this.toolbarLoaded) return; this.toolbarLoaded = true; const { ToolbarModule, ToolbarComponent } = await import("./toolbar/toolbar.module"); const moduleRef = createNgModuleRef(ToolbarModule, this._injector); const { injector } = moduleRef; const componentRef = this.toolbarViewRef.createComponent(ToolbarComponent, { injector, ngModuleRef: moduleRef, });}
登录后复制
此时再来看下这番操作后执行ng build
打包的尺寸大小
可以看到首屏尺寸没有开头那么离谱了, 原因是没有在AppModule
和AppComponent
直接导入ToolbarModule
和ToolbarComponent
, ToolbarModule
被打进了另外的js文件中(Lazy Chunk Files), 当首次点击显示
按钮时, 就会加载这个包含ToolbarModule
的js文件
注意看下面的gif演示中, 首次点击显示
按钮, 浏览器网络调试工具中会多出一个对src_app_toolbar_toolbar_module_ts.js
文件的请求
更多编程相关知识,请访问:编程视频!!
以上就是聊聊Angular中懒加载模块并动态显示它的组件的详细内容,更多请关注php中文网其它相关文章!