手写qiankun-页面渲染

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
  }
}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值