Angular中懒加载一个模块并动态创建显示该模块下声明的组件

这篇具有很好参考价值的文章主要介绍了Angular中懒加载一个模块并动态创建显示该模块下声明的组件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

环境: Angular 13.x.x

angular中支持可以通过路由来懒加载某些页面模块已达到减少首屏尺寸, 提高首屏加载速度的目的. 但是这种通过路由的方式有时候是无法满足需求的.

比如, 点击一个按钮后显示一行工具栏, 这个工具栏组件我不希望它默认打包进main.js, 而是用户点按钮后动态把组件加载并显示出来.

那为什么要动态加载呢? 如果直接在目标页面组件引入工具栏组件, 那么工具栏组件中的代码就会被打包进目标页面组件所在的模块, 这会导致目标页面组件所在的模块生成的js体积变大; 通过动态懒加载的方式, 可以让工具栏组件只在用户点了按钮后再加载, 这样就可以达到减少首屏尺寸的目的.

为了演示, 新建一个angular项目, 然后再新建一个ToolbarModule, 项目的目录结构如图

Angular中懒加载一个模块并动态创建显示该模块下声明的组件

为了达到演示的目的, 我在ToolbarModule的html模板中放了个将近1m的base64图片, 然后直接在AppModule中引用ToolbarModule, 然后执行ng build, 执行结果如图

Angular中懒加载一个模块并动态创建显示该模块下声明的组件

可以看到打包尺寸到达了1.42mb, 也就是说用户每次刷新这个页面, 不管用户有没有点击显示工具栏按钮, 工具栏组件相关的内容都会被加载出来, 这造成了资源的浪费, 所以下面将ToolbarModuleAppModuleimports声明中移除, 然后在用户点击首次点击显示时懒加载工具栏组件.

懒加载工具栏组件

首先, 新建一个ToolbarModuleToolbarComponent, 并在ToolbarModule声明ToolbarComponent

Angular中懒加载一个模块并动态创建显示该模块下声明的组件

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
<div class="flex">
  <svg t="1652618923451" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2104" width="200" height="200"><path d="M412 618m-348 0a348 348 0 1 0 696 0 348 348 0 1 0-696 0Z" fill="#C9F4EB" p-id="2105"></path><path d="M673.19 393h-333a25 25 0 0 1 0-50h333a25 25 0 0 1 0 50zM600.89 235H423.11C367.91 235 323 190.28 323 135.32v-12.5a25 25 0 0 1 50 0v12.5c0 27.39 22.48 49.68 50.11 49.68h177.78c27.63 0 50.11-22.29 50.11-49.68v-16.5a25 25 0 1 1 50 0v16.5c0 54.96-44.91 99.68-100.11 99.68zM673.19 585.5h-333a25 25 0 0 1 0-50h333a25 25 0 0 1 0 50zM467 778H340a25 25 0 0 1 0-50h127a25 25 0 0 1 0 50z" fill="#087E6A" p-id="2106"></path><path d="M739.76 952H273.62a125.14 125.14 0 0 1-125-125V197a125.14 125.14 0 0 1 125-125h466.14a125.14 125.14 0 0 1 125 125v630a125.14 125.14 0 0 1-125 125zM273.62 122a75.08 75.08 0 0 0-75 75v630a75.08 75.08 0 0 0 75 75h466.14a75.08 75.08 0 0 0 75-75V197a75.08 75.08 0 0 0-75-75z" fill="#087E6A" p-id="2107"></path></svg>
  <svg t="1652618941842"
       class="icon"
       viewBox="0 0 1024 1024"
       version="1.1"
       xmlns="http://www.w3.org/2000/svg"
       p-id="2247"
       width="200"
       height="200">
    <path d="M415 624m-348 0a348 348 0 1 0 696 0 348 348 0 1 0-696 0Z"
          fill="#C9F4EB"
          p-id="2248"></path>
    <path d="M695 790H362a25 25 0 0 1 0-50h333a25 25 0 0 1 0 50zM583 649H362a25 25 0 0 1 0-50h221a25 25 0 0 1 0 50zM262 287H129a25 25 0 0 1 0-50h133a25 25 0 0 1 0 50zM262 455.33H129a25 25 0 1 1 0-50h133a25 25 0 0 1 0 50zM262 623.67H129a25 25 0 0 1 0-50h133a25 25 0 0 1 0 50zM262 792H129a25 25 0 0 1 0-50h133a25 25 0 0 1 0 50z"
          fill="#087E6A"
          p-id="2249"></path>
    <path d="M761.76 964H295.62a125.14 125.14 0 0 1-125-125V209a125.14 125.14 0 0 1 125-125h466.14a125.14 125.14 0 0 1 125 125v630a125.14 125.14 0 0 1-125 125zM295.62 134a75.09 75.09 0 0 0-75 75v630a75.08 75.08 0 0 0 75 75h466.14a75.08 75.08 0 0 0 75-75V209a75.09 75.09 0 0 0-75-75z"
          fill="#087E6A"
          p-id="2250"></path>
    <path d="M617 376H443a25 25 0 0 1 0-50h174a25 25 0 0 1 0 50z"
          fill="#087E6A"
          p-id="2251"></path>
    <path d="M530 463a25 25 0 0 1-25-25V264a25 25 0 0 1 50 0v174a25 25 0 0 1-25 25z"
          fill="#087E6A"
          p-id="2252"></path>
  </svg>
  <img src="<这里应该是一张大小将近1M的base64图片, 内容较大, 就略去了...>" alt="">
</div>

然后再AppComponent的中按钮点击事件处理程序中写加载工具栏模块的代码:

app.component.ts
import { Component, createNgModuleRef, Injector, ViewChild, ViewContainerRef } from '@angular/core';

@Component({
    selector: 'root',
    template: `
               <div class="container h-screen flex items-center flex-col w-100 justify-center">
                 <div class="mb-3"
                      [ngClass]="{ hidden: !isToolbarVisible }">
                   <ng-container #toolbar></ng-container>
                 </div>
                 <div>
                   <button (click)="toggleToolbarVisibility()"
                           class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">{{ isToolbarVisible ? '隐藏' : '显示' }}</button>
                   <p class="mt-3">首屏内容</p>
                 </div>
               </div>
             `,
})
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模板中声明的<ng-container #toolbar></ng-container>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打包的尺寸大小

Angular中懒加载一个模块并动态创建显示该模块下声明的组件

可以看到首屏尺寸没有开头那么离谱了, 原因是没有在AppModuleAppComponent直接导入ToolbarModuleToolbarComponent, ToolbarModule被打进了另外的js文件中(Lazy Chunk Files), 当首次点击显示按钮时, 就会加载这个包含ToolbarModule的js文件

注意看下面的gif演示中, 首次点击显示按钮, 浏览器网络调试工具中会多出一个对src_app_toolbar_toolbar_module_ts.js文件的请求

Angular中懒加载一个模块并动态创建显示该模块下声明的组件文章来源地址https://www.toymoban.com/news/detail-807345.html

到了这里,关于Angular中懒加载一个模块并动态创建显示该模块下声明的组件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Django 动态重新加载模块

    可以将对应的文件路径的具体的module传入 例如 我希望重新加载的模块的路径是:app01/myfile.py 那 file_path  对应就是【\\\'app01/myfile.py\\\'】 那 module 对应就是【\\\'myfile\\\'】 这样带入下面的代码就可以实现django动态重新加载某一模块

    2024年02月15日
    浏览(39)
  • 使用模板创建【vite+vue3+ts】项目出现 “找不到模块‘vue‘或其相应的类型声明” 的解决方案

    项目前台需要使用Vue3+Ts来写一个H5应用,然后我用模板创建 创建完后进入 HelloWorld.vue ,两眼一黑 然后在 tsconfig.json 的 \\\"compilerOptions\\\" 中添加 修改 \\\"moduleResolution\\\" 值为 \\\"node\\\"

    2024年02月17日
    浏览(65)
  • vue如何动态加载显示本地图片资源

    在实际开发中,根据某一个变量动态展示图片的情况有很多。实现方法分打包构建工具的差异而不同。 1、webpack的项目 require引入图片资源 2、vite的项目 new URL(url,base).href 疑问解答:为什么vite项目不可以用require? 原因在于,vite的模块化规范是ES Modules,所以vite项目在打包构建

    2024年02月22日
    浏览(55)
  • element UI级联选择器---动态加载数据,动态控制二级面板的显示与隐藏

     一级数据列表是在页面初始化的时候调用接口返回的数据; 二级数据列表需要在获取到一级数据id的时候调用接口得到数据进行列表渲染; 问题: 使用了el-cascader后发现如果第一次点击父级A获取到二级数据,并且二级面板显示,第二次点击父级B获取到二级数据为[ ],此时

    2024年02月08日
    浏览(43)
  • opencv+图像处理(GUI)1-0图像:创建加载显示保存关闭

    本专栏代码地址 https://github.com/xiawei20161308104/xv_opencv_tutorials 本节代码路径 xv_opencv_tutorials/ImageProcessinginOpenCV/load_img.py 创建窗口 namedWindow 从本地加载图像 imread 在窗口中展示图像 imshow 将图像写入文件 imwrite 关闭窗口 destroyWindow destroyAllWindows opencv提供 cv.namedWindow 函数实现创建一

    2023年04月21日
    浏览(41)
  • C++ 使用动态内存创建一个类

    使用动态内存的一个常见原因是允许多个对象共享相同的状态。 例如,假定我们希望定义一个名为 Blob 的类,保存一组元素。与容器不同,我们希望 Blob 对象的不同拷贝之间 共享相同的元素 。即,当我们拷贝一个 Blob 时,原 Blob 对象及其拷贝应该 引用 相同的底层元素。现

    2024年02月01日
    浏览(37)
  • html中使用Vue+element UI动态创建表单数据不显示问题

    直接上代码:html代码如下 我这里后台数据是模拟的,返回的数据格式:  理想的是页面创建时就向后台获取数据,然后将数据渲染在页面上,可是失败了,但是控制台也没有报错,只有单独绑定数据的ReportTitle渲染成功。      最后问了大佬才发现,因为我用的是Vue2,必须

    2024年02月15日
    浏览(53)
  • 用OpenCV实现创建一个新的图像并排显示左右两个输入图像

    创建一个并排显示左右两个输入图像程序的关键在于正确地使用 OpenCV 的 cv::Mat 类和图像处理函数。 下面是一个简单的示例代码,展示了如何实现这个功能。 这段代码假设你已经有了两个图像文件(左图和右图),并将它们并排显示在一个窗口中。 请确保在您的系统上安装

    2024年01月18日
    浏览(53)
  • 如何在 Angular 中使用懒加载路由

    简介 延迟加载 是一种限制加载用户当前需要的模块的方法。这可以提高应用程序的性能并减小初始捆绑包大小。 默认情况下,Angular 使用 急切加载 来加载模块。这意味着在应用程序运行之前必须加载所有模块。虽然这对许多用例可能是足够的,但在某些情况下,这种加载时

    2024年02月20日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包