mustard-app
Version:
个人前端微应用建设中。。。
157 lines (133 loc) • 4.86 kB
text/typescript
import { SandBox } from './proxy/sandBox';
import { loadHtml } from './utils/source';
import { errorLog } from './utils/log';
import { getURL } from './utils';
import { MustardApp } from './element';
import { addInstance, removeInstance } from './global';
import { MustardState, decodeState, initState } from './proxy/proxyHistory';
import { IAppConstructor, IAppStatus, MustardName, MustardURL, SpurceValue } from './typings';
import { EventCenterMicorLife } from './communication';
export default class App {
baseUrl: MustardURL;
url: MustardURL;
name: MustardName;
container: MustardApp;
sandbox: SandBox;
loadCount: number = 0;
status = IAppStatus.create;
state: MustardState; // document 来源
microLifeCenter: EventCenterMicorLife; // 生命周期通讯
// 存放动态资源
source = {
links: new Map<string, SpurceValue>(), // 存放links
scripts: new Map<string, SpurceValue>(), // 存放scripts
domClick: '\n;' // 存放 dom attrs 上的事件
};
constructor ({ name, url: baseUrl, container }: IAppConstructor) {
this.name = name;
this.baseUrl = baseUrl;
this.container = container;
this.microLifeCenter = new EventCenterMicorLife(this.name);
this.init();
}
// 刷新 卸载->初始化
reload () {
this.unmount(true);
this.init();
}
// 初始化
init () {
this.status = IAppStatus.create;
this.microLifeCenter.dispatchLife(this.status);
// 初始化立刻存入 mustardAppInfos.appInstanceMap
addInstance(this.name, this);
this.loadCount = 0;
// 设置资源的真正地址
this.url = getURL(this.name, this.baseUrl).href;
this.source = {
links: new Map<string, SpurceValue>(), // 存放links
scripts: new Map<string, SpurceValue>(), // 存放scripts
domClick: '\n;' // 存放 dom attrs 上的事件
};
// 刷新页面时,为了保证 document.origin 正确,默认取history
this.state = decodeState(this.name);
if(!this.state) {
initState(this.name, '', '', this.url);
this.state = decodeState(this.name);
}
this.status = IAppStatus.loading;
this.microLifeCenter.dispatchLife(this.status);
// 加载对应的资源
loadHtml(this);
// 初始化砂箱
this.sandbox = new SandBox(this.name, this.url);
}
// 资源加载完时执行
onLoad (htmlDom: HTMLElement) {
this.loadCount += 1;
// 第二次执行且组件未卸载时执行渲染
if (this.loadCount === 2 && this.status !== IAppStatus.unmount) {
// 执行mount方法
this.mount(htmlDom);
}
}
/**
* 资源加载完成后进行渲染
*/
mount (html: HTMLElement) {
this.sandbox.start();
// 克隆DOM节点
const cloneHtml = html.cloneNode(true);
// 创建一个fragment节点作为模版,这样不会产生冗余的元素
const fragment = document.createDocumentFragment();
Array.from(cloneHtml.childNodes).forEach((node) => {
fragment.appendChild(node);
});
// 将格式化后的DOM结构插入到容器中
this.container.appendChild(fragment);
// 执行js
let scripts = '';
this.source.scripts.forEach((info) => {
scripts += info.code + '\n;';
});
{
(0, eval)(this.sandbox.bindScope(scripts + '\n;' + this.source.domClick));
}
// 标记应用为已渲染
this.status = IAppStatus.mount;
this.microLifeCenter.dispatchLife(this.status);
}
/**
* 卸载应用
* 执行关闭沙箱,清空缓存等操作
* @param destory 是否销毁应用
*/
unmount (destory: boolean) {
this.sandbox.stop(); // 暂停沙箱
this.status = IAppStatus.unmount;
this.microLifeCenter.dispatchLife(this.status);
if (destory) {
this.destory();
}
}
/**
* 销毁应用
*/
destory () {
this.sandbox = null;
this.container.innerHTML = '';
this.status = IAppStatus.destory;
this.microLifeCenter.dispatchLife(this.status);
removeInstance(this.name);
}
/**
* 子应用加载失败
* @param error 失败原因
*/
error (error: Error): void {
errorLog(error);
this.status = IAppStatus.error;
this.microLifeCenter.dispatchLife(this.status);
this.microLifeCenter = null;
}
}