设置环境变量
- 我们完成了子应用页面的显示,但是由于我们之前设置的
window.__MICRO_WEB__
从来没有改变过,进入子应用时,会重复进行渲染,我们可以看下子应用设置的逻辑 ```javascript function render() { instance = createApp(App); instance .use(router) .mount(‘#app’); } // 一直会执行到这里面 if (!window.MICRO_WEB) { render(); } export async function bootstrap() { console.log(‘vue3.0 app bootstrap’); }
export async function mount(app) { setMain(app) render(); }
export async function unmount(ctx) { instance.unmount(); instance = null; const { container } = ctx if (container) { document.querySelector(container).innerHTML = ‘’ } }
- 除了一直执行`render`方法,子应用的声明周期我们也没有出发到,所以我们要在加载子应用页面的时候,设置`__MICRO_WEB__`为`true`
```javascript
export const loadHtml = async (app) => {
window.__MICRO_WEB__ = true;
}
我们设置
__MICRO_WEB__
为true
后,子应用不再调用render
方法,需要执行mount
声明周期来触发执行render
,我们需要处理我们子应用声明周期的执行获取子应用生命周期
我们通过执行js脚本,来获取到子应用声明周期
main\micro\sandbox\index.js
// 2. 运行js文件,获取子应用生命周期
// const lifeCycle = performScript(script, app.name);
const lifeCycle = performScriptForEval(script, app.name);
console.log('lifeCycle', lifeCycle);
performScriptForEval执行内容
const scriptText =
`() => {
${script}
return window[${appName}]
}`;
return eval(scriptText);
我们获取到的内容是js脚本文件,并不是我们想要的module,这是因为当前返回的window,并不是我们的window对象
我们通过call,将指针指向window,并传入window参数
const scriptText =
`() => {
${script}
return window[${appName}]
}`;
return eval(scriptText).call(window,window);
上面这种方式执行的时候获取不到子应用全局变量,具体原因没找到
- 最终写法都可以获取到子应用声明周期
``javascript // 执行应用的 js 内容 new Function 篇 export const performScript = (script, appName) => { const scriptText =
${script} return window[${appName}] ` return new Function(scriptText).call(window, window);
}
// 执行应用中的 js 内容 eval篇
export const performScriptForEval = (script, appName) => {
// 我们在子应用打包配置中设置了library,全局变量名
// 我们通过执行window.appName 来获取子应用声明周期
const scriptText = (() => () => {
try {
${script}
return window['${appName}']
} catch (err) {
console.error('runScript error:' + err);
}
})()
return (() => eval(scriptText))().call(window, window);
}
![image.png](https://cdn.nlark.com/yuque/0/2022/png/243804/1657875076554-146b24a1-846c-4d93-87a7-ae807ea8d9a3.png#clientId=u71de78f4-5877-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=149&id=u5ffb39ce&margin=%5Bobject%20Object%5D&name=image.png&originHeight=164&originWidth=542&originalType=binary&ratio=1&rotation=0&showTitle=false&size=14833&status=done&style=none&taskId=u262a10a2-2bd8-4198-9ebc-d8f3755e56a&title=&width=492.7272620476969)
<a name="WkbwX"></a>
# 将声明周期挂载到app上
```javascript
// 判断是否有生命周期
function isCheckLiftCycle(lifeCycle) {
return lifeCycle && lifeCycle.bootstrap && lifeCycle.mount && lifeCycle.unmount;
}
// 将子应用生命周期挂载到app上
// beforeLoaded 生命周期执行完之后,我们挂载了子应用这些生命周期,所以后面生命周期都会触发到
if (isCheckLiftCycle(lifeCycle)) {
app.bootstrap = lifeCycle.bootstrap;
app.mount = lifeCycle.mount;
app.unmount = lifeCycle.unmount;
}
- 我们需要先判断子应用是否有生命周期,再将其挂载到子应用app上
- 此时,主应用
beforeLoaded
生命周期执行完,开始执行mounted
,这个时候,我们就能执行到子应用app上的mount
方法,在子应用中做渲染处理// 子应用 export async function mount(app) { console.log('mount'); setMain(app) render(); }