shadow root

This commit is contained in:
Gabe Yuan
2023-08-25 17:07:53 +08:00
parent 6b35525207
commit 86bc915d74
4 changed files with 123 additions and 61 deletions

View File

@@ -15,15 +15,58 @@
max-height: 1.2em; max-height: 1.2em;
} }
</style> </style>
<script>
document.addEventListener("DOMContentLoaded", function () {
(() => {
var shadow = document.querySelector("#shadow1");
var root = shadow.attachShadow({ mode: "open" });
var newLine = document.createElement("p");
newLine.innerText = "new line";
root.appendChild(newLine);
})();
setTimeout(function () {
var shadow = document.querySelector("#shadow2");
var root = shadow.attachShadow({ mode: "open" });
}, 1000);
setTimeout(() => {
var newLine = document.createElement("p");
newLine.innerText = "new line";
var shadow = document.querySelector("#shadow2");
shadow.shadowRoot.appendChild(newLine);
}, 2000);
setTimeout(() => {
var newLine = document.createElement("div");
newLine.innerHTML = "<p>second line</p><p>third line</p>";
var shadow = document.querySelector("#shadow2");
shadow.shadowRoot.appendChild(newLine);
}, 3000);
setTimeout(function () {
var el = document.querySelector("h2");
el.innerText = "hello world";
var title = document.querySelector("#addtitle");
title.innerHTML =
"<div><p>second title</p><ul><li><p>second title</p></li></ul></div>";
}, 1000);
});
</script>
</head> </head>
<body> <body>
<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>
<p>React is a JavaScript library for building user interfaces.</p>
</h2>
<div id="addtitle"></div> <div id="addtitle"></div>
<h2>Shadow 1</h2> <h2>Shadow 1</h2>
<div id="shadow1"></div> <div id="shadow1"></div>
<h2>Shadow 2</h2>
<div id="shadow2"></div>
<br /> <br />
<br /> <br />
<br /> <br />
@@ -102,8 +145,6 @@
Weve first shared our research on RSC in an introductory talk and an Weve first shared our research on RSC in an introductory talk and an
RFC. RFC.
</h2> </h2>
<h2>Shadow 2</h2>
<div id="shadow2"></div>
<br /> <br />
<br /> <br />
<br /> <br />
@@ -236,29 +277,5 @@
To begin the development, run `npm start` or `yarn start`. To begin the development, run `npm start` or `yarn start`.
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>
setTimeout(function () {
for (var i = 1; i <= 2; i++) {
var shadow = document.querySelector("#shadow" + i);
var cont = document.querySelector(".cont" + i);
var root = shadow.attachShadow({ mode: "open" });
// 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>
</body> </body>
</html> </html>

View File

@@ -1,11 +1,12 @@
import { import {
DEFAULT_SELECTOR, DEFAULT_SELECTOR,
GLOBAL_KEY, GLOBAL_KEY,
SHADOW_KEY,
DEFAULT_RULE, DEFAULT_RULE,
BUILTIN_RULES, BUILTIN_RULES,
} from "./rules"; } from "./rules";
export { I18N, UI_LANGS } from "./i18n"; export { I18N, UI_LANGS } from "./i18n";
export { GLOBAL_KEY, DEFAULT_RULE, BUILTIN_RULES }; export { GLOBAL_KEY, SHADOW_KEY, DEFAULT_RULE, BUILTIN_RULES };
const APP_NAME = process.env.REACT_APP_NAME.trim().split(/\s+/).join("-"); const APP_NAME = process.env.REACT_APP_NAME.trim().split(/\s+/).join("-");

View File

@@ -4,6 +4,8 @@ export const DEFAULT_SELECTOR = `:is(${els})`;
export const GLOBAL_KEY = "*"; export const GLOBAL_KEY = "*";
export const SHADOW_KEY = ">>>";
export const DEFAULT_RULE = { export const DEFAULT_RULE = {
pattern: "", pattern: "",
selector: "", selector: "",

View File

@@ -7,6 +7,7 @@ import {
MSG_TRANS_CURRULE, MSG_TRANS_CURRULE,
OPT_STYLE_DASHLINE, OPT_STYLE_DASHLINE,
OPT_STYLE_FUZZY, OPT_STYLE_FUZZY,
SHADOW_KEY,
} from "../config"; } from "../config";
import Content from "../views/Content"; import Content from "../views/Content";
import { fetchUpdate, fetchClear } from "./fetch"; import { fetchUpdate, fetchClear } from "./fetch";
@@ -33,7 +34,10 @@ export class Translator {
"option", "option",
"head", "head",
"script", "script",
"iframe",
]; ];
_rootNodes = new Set();
_tranNodes = new Set();
// 显示 // 显示
_interseObserver = new IntersectionObserver( _interseObserver = new IntersectionObserver(
@@ -57,7 +61,7 @@ export class Translator {
!this._skipNodeNames.includes(mutation.target.localName) && !this._skipNodeNames.includes(mutation.target.localName) &&
mutation.addedNodes.length > 0 mutation.addedNodes.length > 0
) { ) {
const addedNodes = Array.from(mutation.addedNodes).filter((node) => { const nodes = Array.from(mutation.addedNodes).filter((node) => {
if ( if (
this._skipNodeNames.includes(node.localName) || this._skipNodeNames.includes(node.localName) ||
node.id === APP_LCNAME node.id === APP_LCNAME
@@ -66,7 +70,9 @@ export class Translator {
} }
return true; return true;
}); });
if (addedNodes.length > 0) { if (nodes.length > 0) {
// const rootNode = mutation.target.getRootNode();
// todo
this._reTranslate(); this._reTranslate();
} }
} }
@@ -136,27 +142,67 @@ export class Translator {
this.rule = { ...this.rule, textStyle }; this.rule = { ...this.rule, textStyle };
}; };
_queryFilter = (selector, rootNode) => {
return Array.from(rootNode.querySelectorAll(selector)).filter(
(node) => this._queryFilter(selector, node).length === 0
);
};
_queryNodes = (rootNode = document) => { _queryNodes = (rootNode = document) => {
const childRoots = Array.from(rootNode.querySelectorAll("*")) // const childRoots = Array.from(rootNode.querySelectorAll("*"))
.map((item) => item.shadowRoot) // .map((item) => item.shadowRoot)
.filter(Boolean); // .filter(Boolean);
const childNodes = childRoots.map((item) => this._queryNodes(item)); // const childNodes = childRoots.map((item) => this._queryNodes(item));
const nodes = Array.from(rootNode.querySelectorAll(this.rule.selector)); // const nodes = Array.from(rootNode.querySelectorAll(this.rule.selector));
return nodes.concat(childNodes).flat(); // return nodes.concat(childNodes).flat();
this._rootNodes.add(rootNode);
this._rule.selector
.split(";")
.map((item) => item.trim())
.filter(Boolean)
.forEach((selector) => {
if (selector.includes(SHADOW_KEY)) {
const [outSelector, inSelector] = selector
.split(SHADOW_KEY)
.map((item) => item.trim());
if (outSelector && inSelector) {
const outNodes = rootNode.querySelectorAll(outSelector);
outNodes.forEach((outNode) => {
if (outNode.shadowRoot) {
this._rootNodes.add(outNode.shadowRoot);
this._queryFilter(inSelector, outNode.shadowRoot).forEach(
(item) => {
this._tranNodes.add(item);
}
);
}
});
}
} else {
this._queryFilter(selector, rootNode).forEach((item) => {
this._tranNodes.add(item);
});
}
});
}; };
_register = () => { _register = () => {
// 搜索节点
this._queryNodes();
this._rootNodes.forEach((node) => {
// 监听节点变化; // 监听节点变化;
this._mutaObserver.observe(document, { this._mutaObserver.observe(node, {
childList: true, childList: true,
subtree: true, subtree: true,
// characterData: true, // characterData: true,
}); });
});
this._tranNodes.forEach((node) => {
// 监听节点显示 // 监听节点显示
this._queryNodes().forEach((el) => { this._interseObserver.observe(node);
this._interseObserver.unobserve(el);
this._interseObserver.observe(el);
}); });
}; };
@@ -164,33 +210,29 @@ export class Translator {
// 解除节点变化监听 // 解除节点变化监听
this._mutaObserver.disconnect(); this._mutaObserver.disconnect();
this._tranNodes.forEach((node) => {
// 解除节点显示监听 // 解除节点显示监听
this._queryNodes().forEach((el) => this._interseObserver.unobserve(el)); this._interseObserver.unobserve(node);
// 移除已插入元素 // 移除已插入元素
this._queryNodes().forEach((el) => { node.querySelector(APP_LCNAME)?.remove();
el?.querySelector(APP_LCNAME)?.remove();
}); });
// 清空节点集合
this._rootNodes.clear();
this._tranNodes.clear();
// 清空任务池 // 清空任务池
fetchClear(); fetchClear();
}; };
_reTranslate = debounce(() => { _reTranslate = debounce(() => {
if (this.rule.transOpen === "true") { if (this._rule.transOpen === "true") {
this._queryNodes().forEach((el) => { this._register();
this._interseObserver.unobserve(el);
this._interseObserver.observe(el);
});
} }
}, 500); }, 500);
_render = (el) => { _render = (el) => {
// 含子元素
if (this._queryNodes(el).length > 0) {
return;
}
// 已翻译 // 已翻译
if (el.querySelector(APP_LCNAME)) { if (el.querySelector(APP_LCNAME)) {
return; return;
@@ -202,7 +244,7 @@ export class Translator {
return; return;
} }
// console.log("---> ", q); // console.log("---> ", el);
const span = document.createElement(APP_LCNAME); const span = document.createElement(APP_LCNAME);
span.style.visibility = "visible"; span.style.visibility = "visible";