Skip to content

Commit

Permalink
fix: 修复svg在append到元素之后ownerdocument失效问题 (#132)
Browse files Browse the repository at this point in the history
  • Loading branch information
yiludege authored Sep 6, 2022
1 parent 48a3569 commit be205d2
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 15 deletions.
15 changes: 9 additions & 6 deletions packages/wujie-core/src/effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
rawRemoveEventListener,
} from "./common";
import { isFunction, isHijackingTag, requestIdleCallback, error, warn, nextTick, getCurUrl } from "./utils";
import { insertScriptToIframe } from "./iframe";
import { insertScriptToIframe, patchElementEffect } from "./iframe";
import Wujie from "./sandbox";
import { getPatchStyleElements } from "./shadow";
import { getCssLoader, getEffectLoaders, isMatchUrl } from "./plugin";
Expand Down Expand Up @@ -70,12 +70,12 @@ function handleStylesheetElementPatch(stylesheetElement: HTMLStyleElement & { _p
* 劫持处理样式元素的属性
*/
function patchStylesheetElement(
stylesheetElement: HTMLStyleElement & { _hasPatch?: boolean },
stylesheetElement: HTMLStyleElement & { _hasPatchStyle?: boolean },
cssLoader: (code: string, url: string, base: string) => string,
sandbox: Wujie,
curUrl: string
) {
if (stylesheetElement._hasPatch) return;
if (stylesheetElement._hasPatchStyle) return;
const innerHTMLDesc = Object.getOwnPropertyDescriptor(Element.prototype, "innerHTML");
const innerTextDesc = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "innerText");
const textContentDesc = Object.getOwnPropertyDescriptor(Node.prototype, "textContent");
Expand Down Expand Up @@ -131,7 +131,7 @@ function patchStylesheetElement(
} else return rawAppendChild(node);
},
},
_hasPatch: { get: () => true },
_hasPatchStyle: { get: () => true },
});
}

Expand All @@ -148,11 +148,14 @@ function rewriteAppendOrInsertChild(opts: {
const { rawDOMAppendOrInsertBefore, wujieId } = opts;
const sandbox = getWujieById(wujieId);

const { styleSheetElements, replace, fetch, plugins, iframe, lifecycles, proxyLocation } = sandbox;

if (!isHijackingTag(element.tagName) || !wujieId) {
return rawDOMAppendOrInsertBefore.call(this, element, refChild) as T;
const res = rawDOMAppendOrInsertBefore.call(this, element, refChild) as T;
patchElementEffect(element, iframe.contentWindow);
return res;
}

const { styleSheetElements, replace, fetch, plugins, iframe, lifecycles, proxyLocation } = sandbox;
const iframeDocument = iframe.contentDocument;
const curUrl = getCurUrl(proxyLocation);

Expand Down
39 changes: 30 additions & 9 deletions packages/wujie-core/src/iframe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -520,15 +520,29 @@ function patchDocumentEffect(iframeWindow: Window): void {

/**
* patch Node effect
* 1、处理 getRootNode
* 2、处理 appendChild、insertBefore,当插入的节点为 svg 时,createElement 的 patch 会被去除,需要重新 patch
* @param iframeWindow
*/
function patchNodeEffect(iframeWindow: Window): void {
const rawGetRootNode = iframeWindow.Node.prototype.getRootNode;
const rawAppendChild = iframeWindow.Node.prototype.appendChild;
const RawInsertRule = iframeWindow.Node.prototype.insertBefore;
iframeWindow.Node.prototype.getRootNode = function (options?: GetRootNodeOptions): Node {
const rootNode = rawGetRootNode.call(this, options);
if (rootNode === iframeWindow.__WUJIE.shadowRoot) return iframeWindow.document;
else return rootNode;
};
iframeWindow.Node.prototype.appendChild = function <T extends Node>(node: T): T {
const res = rawAppendChild.call(this, node);
patchElementEffect(node, iframeWindow);
return res;
};
iframeWindow.Node.prototype.insertBefore = function <T extends Node>(node: T, child: Node | null): T {
const res = RawInsertRule.call(this, node, child);
patchElementEffect(node, iframeWindow);
return res;
};
}

/**
Expand Down Expand Up @@ -601,16 +615,23 @@ function stopIframeLoading(iframeWindow: Window, url: string) {
});
}

export function patchElementEffect(element: HTMLElement | ShadowRoot, iframeWindow: Window): void {
export function patchElementEffect(
element: (HTMLElement | Node | ShadowRoot) & { _hasPatch?: boolean },
iframeWindow: Window
): void {
const proxyLocation = iframeWindow.__WUJIE.proxyLocation as Location;
Object.defineProperty(element, "baseURI", {
configurable: true,
get: () => proxyLocation.protocol + "//" + proxyLocation.host + proxyLocation.pathname,
set: undefined,
});
Object.defineProperty(element, "ownerDocument", {
configurable: true,
get: () => iframeWindow.document,
if (element._hasPatch) return;
Object.defineProperties(element, {
baseURI: {
configurable: true,
get: () => proxyLocation.protocol + "//" + proxyLocation.host + proxyLocation.pathname,
set: undefined,
},
ownerDocument: {
configurable: true,
get: () => iframeWindow.document,
},
_hasPatch: { get: () => true },
});
}

Expand Down

0 comments on commit be205d2

Please sign in to comment.