fix shadow dom

This commit is contained in:
Gabe Yuan
2023-08-24 14:57:54 +08:00
parent 792a1bfcad
commit a2762e6ce6
3 changed files with 78 additions and 40 deletions

View File

@@ -21,6 +21,7 @@
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"> <div id="root">
<h2>React is a JavaScript library for building user interfaces.</h2> <h2>React is a JavaScript library for building user interfaces.</h2>
<div id="addtitle"></div>
<h2>Shadow 1</h2> <h2>Shadow 1</h2>
<div id="shadow1"></div> <div id="shadow1"></div>
<br /> <br />
@@ -236,13 +237,28 @@
To create a production bundle, use `npm run build` or `yarn build`. To create a production bundle, use `npm run build` or `yarn build`.
--> -->
<script> <script>
for (var i = 1; i <= 2; i++) { setTimeout(function () {
var shadow = document.querySelector("#shadow" + i); for (var i = 1; i <= 2; i++) {
var cont = document.querySelector(".cont" + i); var shadow = document.querySelector("#shadow" + i);
var root = shadow.attachShadow({ mode: "open" }); var cont = document.querySelector(".cont" + i);
// root.appendChild(document.importNode(cont, true)); var root = shadow.attachShadow({ mode: "open" });
root.appendChild(cont.cloneNode(true)); // root.appendChild(document.importNode(cont, true));
} root.appendChild(cont.cloneNode(true));
var newLine = document.createElement("p");
newLine.innerText = "new line";
root.appendChild(newLine);
}
}, 3000);
</script>
<script>
setTimeout(function () {
var el = document.querySelector("h2");
el.innerText = "hello world";
var title = document.querySelector("#addtitle");
title.innerHTML = "<p>second title</p>";
}, 1000);
</script> </script>
</body> </body>
</html> </html>

View File

@@ -10,21 +10,7 @@ import {
} from "../config"; } from "../config";
import Content from "../views/Content"; import Content from "../views/Content";
import { fetchUpdate, fetchClear } from "./fetch"; import { fetchUpdate, fetchClear } from "./fetch";
import { debounce } from "./utils";
/**
* 获取节点列表并转为数组
* @param {*} selector
* @param {*} rootNode
* @returns
*/
function queryNodes(selector, rootNode = document) {
const childRoots = Array.from(rootNode.querySelectorAll("*"))
.map((item) => item.shadowRoot)
.filter(Boolean);
const childNodes = childRoots.map((item) => queryNodes(selector, item));
const nodes = Array.from(rootNode.querySelectorAll(selector));
return nodes.concat(childNodes).flat();
}
/** /**
* 翻译类 * 翻译类
@@ -33,6 +19,7 @@ export class Translator {
_rule = {}; _rule = {};
_minLength = 0; _minLength = 0;
_maxLength = 0; _maxLength = 0;
_skipNodeNames = [APP_LCNAME, "style", "svg", "img"];
// 显示 // 显示
_interseObserver = new IntersectionObserver( _interseObserver = new IntersectionObserver(
@@ -52,20 +39,35 @@ export class Translator {
// 变化 // 变化
_mutaObserver = new MutationObserver((mutations) => { _mutaObserver = new MutationObserver((mutations) => {
mutations.forEach((mutation) => { mutations.forEach((mutation) => {
mutation.addedNodes.forEach((node) => { if (
try { mutation.target.localName !== APP_LCNAME &&
queryNodes(this.rule.selector, node).forEach((el) => { mutation.addedNodes.length > 0
this._interseObserver.observe(el); ) {
}); const addedNodes = Array.from(mutation.addedNodes).filter((node) => {
} catch (err) { if (!this._skipNodeNames.includes(node.localName)) {
// return true;
}
return false;
});
if (addedNodes.length > 0) {
this._reTranslate();
} }
}); }
}); });
}); });
_overrideAttachShadow = () => {
const _this = this;
const _attachShadow = HTMLElement.prototype.attachShadow;
HTMLElement.prototype.attachShadow = function () {
_this._reTranslate();
return _attachShadow.apply(this, arguments);
};
};
constructor(rule, { fetchInterval, fetchLimit, minLength, maxLength }) { constructor(rule, { fetchInterval, fetchLimit, minLength, maxLength }) {
fetchUpdate(fetchInterval, fetchLimit); fetchUpdate(fetchInterval, fetchLimit);
this._overrideAttachShadow();
this._minLength = minLength ?? TRANS_MIN_LENGTH; this._minLength = minLength ?? TRANS_MIN_LENGTH;
this._maxLength = maxLength ?? TRANS_MAX_LENGTH; this._maxLength = maxLength ?? TRANS_MAX_LENGTH;
this.rule = rule; this.rule = rule;
@@ -116,16 +118,27 @@ export class Translator {
this.rule = { ...this.rule, textStyle }; this.rule = { ...this.rule, textStyle };
}; };
_queryNodes = (rootNode = document) => {
const childRoots = Array.from(rootNode.querySelectorAll("*"))
.map((item) => item.shadowRoot)
.filter(Boolean);
const childNodes = childRoots.map((item) => this._queryNodes(item));
const nodes = Array.from(rootNode.querySelectorAll(this.rule.selector));
return nodes.concat(childNodes).flat();
};
_register = () => { _register = () => {
// 监听节点变化; // 监听节点变化;
this._mutaObserver.disconnect();
this._mutaObserver.observe(document, { this._mutaObserver.observe(document, {
childList: true, childList: true,
subtree: true, subtree: true,
characterData: true, // characterData: true,
}); });
// 监听节点显示 // 监听节点显示
queryNodes(this.rule.selector).forEach((el) => { this._queryNodes().forEach((el) => {
this._interseObserver.unobserve(el);
this._interseObserver.observe(el); this._interseObserver.observe(el);
}); });
}; };
@@ -135,12 +148,10 @@ export class Translator {
this._mutaObserver.disconnect(); this._mutaObserver.disconnect();
// 解除节点显示监听 // 解除节点显示监听
queryNodes(this.rule.selector).forEach((el) => this._queryNodes().forEach((el) => this._interseObserver.unobserve(el));
this._interseObserver.unobserve(el)
);
// 移除已插入元素 // 移除已插入元素
queryNodes(this.rule.selector).forEach((el) => { this._queryNodes().forEach((el) => {
el?.querySelector(APP_LCNAME)?.remove(); el?.querySelector(APP_LCNAME)?.remove();
}); });
@@ -148,9 +159,18 @@ export class Translator {
fetchClear(); fetchClear();
}; };
_reTranslate = debounce(() => {
if (this.rule.transOpen === "true") {
this._queryNodes().forEach((el) => {
this._interseObserver.unobserve(el);
this._interseObserver.observe(el);
});
}
}, 500);
_render = (el) => { _render = (el) => {
// 含子元素 // 含子元素
if (queryNodes(this.rule.selector, el).length > 0) { if (this._queryNodes(el).length > 0) {
return; return;
} }
@@ -172,8 +192,10 @@ export class Translator {
el.appendChild(span); el.appendChild(span);
el.style.cssText += el.style.cssText +=
"-webkit-line-clamp: unset; max-height: none; height: auto;"; "-webkit-line-clamp: unset; max-height: none; height: auto;";
el.parentElement.style.cssText += if (el.parentElement) {
"-webkit-line-clamp: unset; max-height: none; height: auto;"; el.parentElement.style.cssText +=
"-webkit-line-clamp: unset; max-height: none; height: auto;";
}
const root = createRoot(span); const root = createRoot(span);
root.render(<Content q={q} translator={this} />); root.render(<Content q={q} translator={this} />);

View File

@@ -39,7 +39,7 @@ import { isGm } from "./libs/browser";
const $action = document.createElement("div"); const $action = document.createElement("div");
$action.setAttribute("id", "kiss-translator"); $action.setAttribute("id", "kiss-translator");
document.body.parentElement.appendChild($action); document.body.parentElement.appendChild($action);
const shadowContainer = $action.attachShadow({ mode: "open" }); const shadowContainer = $action.attachShadow({ mode: "closed" });
const emotionRoot = document.createElement("style"); const emotionRoot = document.createElement("style");
const shadowRootElement = document.createElement("div"); const shadowRootElement = document.createElement("div");
shadowContainer.appendChild(emotionRoot); shadowContainer.appendChild(emotionRoot);