手写qiankun-页面渲染

news2024/11/15 23:50:26

registerMicroApps配置子应用

start读取配置,拉取子应用并完成渲染

//全局变量
let _app = [];

//更好的获取全局变量_app
export const getApps = () => _app;

//app为传递过来的子应用数组
export const registerMicroApps = (app) => {
  _app = app;
};

export const start = () => {
};

监控路由变化

import { getApps } from "./index.js"
import { fetchSource } from "./utils.js";

export const handleRouter = async () => { 
  const apps = getApps();
  const app = apps.find(item => item.activeRule === window.location.pathname)
  
  if (!app) { 
    return;
  }
  try {
    const html = await fetchSource(app.entry);
    const container = document.querySelector(app.container);
    container.innerHTML = html;
  } catch (e) { 
    console.log(e);
  }
}

获取script并执行

完成getExternalScriptsexecScripts函数

import { fetchSource } from "./utils.js";
export const importEntry = async (entry, options) => { 
  const content = await fetchSource(entry);
  let template = document.createElement('div');
  template.setAttribute('data-name', options.name);
  template.innerHTML = content;

  //数据存放缓存
  const source = {
    links: new Map(),
    scripts: new Map()
  }

  const children = Array.from(template.children);

  const scripts = children.filter(item => item.tagName === 'SCRIPT');

  scripts.forEach(dom => { 
    const src = dom.getAttribute('src');
    if (src) { 
      source.scripts.set(src, {
        code: "", //具体js的代码内容,需要通过远程获取
        isExternal:true,//是否是外链js
      })
    }
    else if (dom.textContent) { //内链js
      //随机名字,当做缓存键名
      const randomName = Math.random().toString(36).substring(2,15);
      source.scripts.set(randomName, {
        code: dom.textContent, 
        isExternal:false,
      })
    }
  });

  console.log(source);

  const assetPublicPath = options.name;

  const getExternalScripts = () => { 
    //先将map中的内容转换成数组
    const scriptEntries = Array.from(source.scripts.entries());
    //声明远程获取的promise数组
    const fetchScriptPromise = [];
    for (let [url, info] of scriptEntries) { 
      console.log(url, info);
      //这里的url可能是本地的相对地址
      //由于我们有基座引用,如果是相对地址,就会到基座的下面去查找js文件
      //所以这里需要将相对地址转换为子应用绝对地址
      if (!url.includes('http') && info.isExternal) {
        url = `${entry.endsWith('/') ? entry.substring(0, entry.length - 1) : entry}${url}`;
      }
      console.log(url)
      //放入promise到数组中
      fetchScriptPromise.push(info.code ? Promise.resolve(info.code) : fetchSource(url));
    }

    return Promise.all(fetchScriptPromise)
  }

  const execScripts = async () => {
    const scriptEntries = Array.from(source.scripts.entries());
    const scripts = await getExternalScripts();
    scripts.forEach((code, i) => { 
      scriptEntries[i][1].code = code;
      eval(code);
    });

    console.log(source);
  }
}

部分代码

import { fetchSource } from './utils';

export const importEntry = async (entry,options) => {
  //远程获取html字符串内容
  const html = await fetchSource(entry);
  let template = document.querySelector(`div[data-name=${options.name}]`);
  console.log("template",template);
  //如果没有template的div容器,就创建一个新的
  if(!template){
    template = document.createElement('div');
    template.setAttribute('data-name',options.name);
    template.innerHTML = html;
  }

  //设置缓存
  const source = {
    scripts: new Map()
  }

  //template.children 是一个伪数组
  const children = Array.from(template.children);

  //获取所有的script标签
  const scripts = children.filter(item => item.tagName === 'SCRIPT');

  scripts.forEach(dom => {
    const src = dom.getAttribute('src');
    if(src){
      source.scripts.set(src,{
        code:'', //如果是外链的script,还需要通过远程获取
        isExternal:true //是否是外链js
      });
    }
    else if(dom.textContent){
      //内链js
      //随机给一个map的键名
      const randomName = Math.random().toString(36).substring(2,15);
      source.scripts.set(randomName,{
        code:dom.textContent,
        isExternal:false
      })
    }
  })

  const getExternalScripts = () => {
    //获取缓存中存放的所有外链script地址
    const scriptEntries = Array.from(source.scripts.entries());

    const fetchScriptPromise = [];

    for(let [url,info] of scriptEntries){
      console.log(url,info);
      //这里的url可能是本地的绝对地址 /开头,也可能是远程的绝对地址 http开头
      //如果是本地的绝对地址,需要拼接上子应用的地址
      //因为/开头的话,在基座应用中,加上的就是基座应用的域名地址
      if(!url.includes('http') && info.isExternal){
        url = `${entry.endsWith('/') ? entry.substring(0,entry.length-1) : entry}${url}`;
        console.log("----",url)
      }

      //info.code如果有,表明是内链的js
      fetchScriptPromise.push(info.code ? Promise.resolve(info.code) : fetchSource(url));
    }

    console.log(fetchScriptPromise);

    return Promise.all(fetchScriptPromise);
  };

  const execScripts = async () => {
    //获取缓存中存放的所有外链script地址
    const scriptEntries = Array.from(source.scripts.entries());
    const scripts = await getExternalScripts();

    scripts.forEach((code,i) => {
      scriptEntries[i][1].code = code;
      eval(code);
    })

  };

  return {
    template,
    getExternalScripts,
    execScripts
  }
}

页面效果
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2039150.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

http中get和post怎么选

5.4.2.怎么选择1.如果你是想从服务器上获取资源,建议使用GET请求,如果你这个请求是为了向服务器提交数据,建议使用POST请求。2.大部分的form表单提交,都是post方式,因为form表单中要填写大量的数据,这些数据…

RK3399平台开发系列讲解(内核入门篇)详解内联汇编

🚀返回专栏总目录 文章目录 一、C语言实现加法二、使用汇编函数实现加法三、内联汇编语法四、使用案例沉淀、分享、成长,让自己和他人都能有所收获!😄 📢要深入理解Linux内核中的同步与互斥的实现,需要先了解一下内联汇编:在C函数中使用汇编代码。 现代编译器已经足…

Linux系统调试课:CPUFreq 中央处理器频率调节技术

文章目录 一、CPUFreq组成二、用户接口三、设备树配置沉淀、分享、成长,让自己和他人都能有所收获!😄 📢中央处理器频率调节(Central Processing Unit frequency,CPUFreq)技术可以降低ARM芯片的功耗,例如在系统对任务压力较小时,通过调整处理器工作频率与输入电压的…

【一图学技术】9.OAuth2.0授权框架SSO单点登录图解及关系区别、使用场景

OAuth2.0原理&SSO单点登录图解 一、单点登录SSO 1.概述 ​ 单点登录(全称Single Sign On,简称就是SSO)是一种身份验证和授权机制,它允许用户在多个相关但相互独立的系统或应用程序之间进行无缝切换,而无需重复登录。在多个…

【3】MySQL的安装即启动

目录 一.下载 二.安装 三.启动 一.下载 二.安装 安装MySQL时遇到的Initializing database错误:推荐下面的博客(简单就是电脑名不要出现中文) https://blog.csdn.net/m0_52775858/article/details/123705566 三.启动 PS:cmd要…

多台USB 3.0相机启动时部分相机无法打开

在使用多台USB 3.0相机时,遇到启动时部分相机无法打开的问题是较为常见的情况。这个问题通常与带宽、供电、驱动程序、或系统资源管理有关。以下是一些优化建议,帮助你提高相机启动的可靠性: 1. USB带宽管理 USB 3.0的带宽虽然比USB 2.0高很…

自训Transformer模型:识别图像是否由AI生成?

背景 随着AI生成图像技术的迅猛发展,特别是生成对抗网络(GANs)和深度学习的不断进步,生成的图像变得越来越逼真。 这项技术不仅催生了许多创新应用,也带来了潜在的风险和挑战。 Transformer模型在图像识别中的作用 …

PHP初级栈进阶篇

小刘小刘,下雨不愁 (收藏,关注不迷路) 这里我会更新一些php进阶知识点,新手想再进一步可以有个方向,也有个知识图谱的普及 当然本篇不止写技术 会涉及一些进阶路线 我也是在这里积累,希望和同行者一起进步为后来者…

网络协议四 物理层,数据链路层,数字信号,模拟信号,信道,CSMA/CD协议-以太网帧协议,PPP协议,网卡

从这一节开始学习 五层模型。学习方法是从最底层物理层开始学习 七层模型 五层模型 各个层用的协议,以及加上协议后的称谓 各个层的作用 应用层:可以认为是原始数据,该数据称为 报文,用户数据。 运输层:也叫传输层&am…

猫头虎 分享:Python库 Pytest 的简介、安装、用法详解入门教程

猫头虎 分享:Python库 Pytest 的简介、安装、用法详解入门教程 🚀 今天猫头虎带您深入了解 Python 测试框架 Pytest 的强大功能,手把手教您从安装到实际使用,助您轻松提升代码质量!😺 摘要 📋 …

Windows蓝屏事件:深入分析与未来启示

引言 在2024年7月19日,一起引发全球范围蓝屏问题的事件,将安全领域领先的公司CrowdStrike推向了舆论的风口浪尖。尽管事后CrowdStrike发布了一份长达12页的根本原因分析(RCA),试图解释并缓解这一问题,但该…

学习笔记 韩顺平 零基础30天学会Java(2024.8.14)

P500 集合体系图 单列集合是指自己只有一个值,双列集合是像键值对这样的 P501 Collection方法 对于第三点,像Set这样的,存放进去的和取出来的顺序可能不是一样的,所以就叫无序的 P502 迭代器遍历 在调用iterator.next()方法之前必…

新160个crackme - 030-Acid Bytes.4

运行分析 需要破解Name和Serial PE分析 upx壳,32位 linux系统upx -d 脱壳 脱壳后发现是Delphi程序 静态分析&动态调试 ida搜索字符串,找到Your Name must be at least 6 Chars long !,双击进入 发现地址为红色,即函数未定义 选…

grpc简单知识

目录 gRPC简介 RPC(远程过程调用)的定义与重要性 gRPC的设计目标与使用场景 ​编辑gRPC调用方式 Unary RPC:一元RPC Server-side streaming RPC:服务端流式RPC Client-side streaming RPC:客户端流式RPC Bidirecti…

Midjourney应用-用AI帮你做广告视频(动物走秀视频制作)

​ 前言/introduction 在之前的教程里我们讲过动物拟人化图片的生成。 这篇我们讲下这种图片的一种应用: 动物走秀视频广告制作方法 使用工具: MidjourneyAI视频生成工具(即梦AI/可灵AI/runway) 操作方法 step1-Midjourney出图 …

从数字化到数智化:消费零售企业如何实现门店数智化管理?

随着信息技术的飞速发展,数字化已成为企业转型的必经之路。然而,数字化本身并不是目的,而是通往数智化的桥梁。数智化,即数据智能化,是指企业通过数字化手段收集和分析数据,进而利用这些数据驱动决策和创新…

气象大数据案例项目(求各气象站的平均气温)

气象大数据案例项目(求各气象站的平均气温) 一、项目需求二、数据格式三、项目开发3.1 在windows 进行开发3.2 运行结果3.3 对项目打包 一、项目需求 现在有一份来自美国国家海洋和大气管理局的数据集,里面包含近30年每个气象站、每小时的天…

C++ 面向对象技术实战:实现基于 POSIX 线程标准封装的线程池

线程池基础概述 为什么要有线程池?假设没有使用线程池时,一个请求用一个子线程来处理。每来一个请求,都得创建子线程,子线程执行请求,关闭子线程。当请求量(并发)比较大的时候,频繁…

新能源遇“秋老虎”,8月第二周销量集体下滑,问界惨遭腰斩

文/王俣祺 导语:随着日前7月份乘用车销量的公布,我们发现7月并没有因6月各车企的“冲量”行为迎来反噬,对于这种“淡季不淡”的现象市场上一片看好。但从近日公布的8月销量数据来看,人们对于“秋老虎”的恐怖可以说是一无所知。随…

MySQL学习[5] ——MySQL日志

五、MySQL日志 5.1 MySQL中有哪些日志? MySQL中主要有三种日志:undo log(回滚日志)、redo log(重做日志)、binlog(归档日志),简单介绍: undo log&#xff…