长沙哪里有创建网站的公司网页设计代做
我们接着上一节的《从源码看无界 1.0.28:为何说它是 qiankun 的 “轻量化替代方案”》内容继续往下。
生命周期图
sandbox.active 方法
我们找到 packages/wujie-core/src/sandbox.ts 文件的第 275 行:
//.../** 激活子应用* 1、同步路由* 2、动态修改iframe的fetch* 3、准备shadow* 4、准备子应用注入*/
public async active(options: {url: string;sync?: boolean;prefix?: { [key: string]: string };template?: string;el?: string | HTMLElement;props?: { [key: string]: any };alive?: boolean;fetch?: (input: RequestInfo, init?: RequestInit) => Promise<Response>;replace?: (code: string) => string;
}): Promise<void> {//...// 设置loadingaddLoading(el, loading);const newSandbox = new WuJie({ name, url, attrs, degradeAttrs, fiber, degrade, plugins, lifecycles });newSandbox.lifecycles?.beforeLoad?.(newSandbox.iframe.contentWindow);const { template, getExternalScripts, getExternalStyleSheets } = await importHTML({url,html,opts: {fetch: fetch || window.fetch,plugins: newSandbox.plugins,loadError: newSandbox.lifecycles.loadError,fiber,},});const processedHtml = await processCssLoader(newSandbox, template, getExternalStyleSheets);await newSandbox.active({ url, sync, prefix, template: processedHtml, el, props, alive, fetch, replace });await newSandbox.start(getExternalScripts);return () => newSandbox.destroy();
}
//...
主子应用路由同步
可以看到,首先将主应用的路由同步到子应用中,然后再把子应用的路由同步到主应用中:
// 处理子应用路由同步if (this.execFlag && this.alive) {// 当保活模式下子应用重新激活时,只需要将子应用路径同步回主应用syncUrlToWindow(iframeWindow);} else {// 先将url同步回iframe,然后再同步回浏览器urlsyncUrlToIframe(iframeWindow);syncUrlToWindow(iframeWindow);}//.../*** 同步主应用路由到子应用*/
export function syncUrlToIframe(iframeWindow: Window): void {// ...if (preAppRoutePath !== appRoutePath) {iframeWindow.history.replaceState(null, "", inject.mainHostPath + appRoutePath);}
}/*** 同步子应用路由到主应用路由*/
export function syncUrlToWindow(iframeWindow: Window): void {//...if (winUrlElement.href !== window.location.href) {window.history.replaceState(null, "", winUrlElement.href);}winUrlElement = null;
}
可以看到同步路由也是很简单,直接调用 history 的 replaceState 方法把主应用跟子应用的 history 改掉了。
接来下可以看到 active 方法中的这段代码:
我们接着上一节的《从源码看无界 1.0.28:为何说它是 qiankun 的 “轻量化替代方案”》内容继续往下。
生命周期图
sandbox.active 方法
我们找到 packages/wujie-core/src/sandbox.ts 文件的第 139 行:
//.../** 激活子应用* 1、同步路由* 2、动态修改iframe的fetch* 3、准备shadow* 4、准备子应用注入*/
public async active(options: {url: string;sync?: boolean;prefix?: { [key: string]: string };template?: string;el?: string | HTMLElement;props?: { [key: string]: any };alive?: boolean;fetch?: (input: RequestInfo, init?: RequestInit) => Promise<Response>;replace?: (code: string) => string;
}): Promise<void> {//...if (this.shadowRoot) {/*document.addEventListener was transfer to shadowRoot.addEventListenerreact 16 SyntheticEvent will remember document event for avoid repeat listenshadowRoot have to dispatchEvent for react 16 so can't be destroyedthis may lead memory leak risk*/this.el = renderElementToContainer(this.shadowRoot.host, el);if (this.alive) return;} else {// 预执行无容器,暂时插入iframe内部触发Web Component的connectconst iframeBody = rawDocumentQuerySelector.call(iframeWindow.document, "body") as HTMLElement;this.el = renderElementToContainer(createWujieWebComponent(this.id), el ?? iframeBody);}await renderTemplateToShadowRoot(this.shadowRoot, iframeWindow, this.template);this.patchCssRules();// inject shadowRoot to appthis.provide.shadowRoot = this.shadowRoot;
}
我们第一次渲染子应用的时候,这个 shadowRoot 对象肯定是没有初始化的,所以会走以下代码:
// 预执行无容器,暂时插入iframe内部触发Web Component的connectconst iframeBody = rawDocumentQuerySelector.call(iframeWindow.document, "body") as HTMLElement;this.el = renderElementToContainer(createWujieWebComponent(this.id), el ?? iframeBody);//...export function createWujieWebComponent(id: string): HTMLElement {const contentElement = window.document.createElement("wujie-app");contentElement.setAttribute(WUJIE_APP_ID, id);contentElement.classList.add(WUJIE_IFRAME_CLASS);return contentElement;}}
创建自定义元素 wujie-app
可以看到,首先调用了 createWujieWebComponent 方法注册了一个自定义元素 wujie-app,那么有小伙伴要问了,这个 “wujie-app” 元素到底是啥?
其实在框架加载的时候就已经往全局注册了一个自定义元素 wujie-app,可以找到 packages/wujie-core/src/index.ts 文件的第 171 行代码:
/*** 定义 wujie webComponent,将shadow包裹并获得dom装载和卸载的生命周期*/
export function defineWujieWebComponent() {const customElements = window.customElements;if (customElements && !customElements?.get("wujie-app")) {class WujieApp extends HTMLElement {connectedCallback(): void {if (this.shadowRoot) return;// 为自定义元素附加一个 Shadow DOM,实现样式和结构的封装const shadowRoot = this.attachShadow({ mode: "open" });const sandbox = getWujieById(this.getAttribute(WUJIE_APP_ID));patchElementEffect(shadowRoot, sandbox.iframe.contentWindow);sandbox.shadowRoot = shadowRoot;}disconnectedCallback(): void {const sandbox = getWujieById(this.getAttribute(WUJIE_APP_ID));sandbox?.