如何替換網頁上的文本,包括使用未來 JavaScript 呼叫注入或修改的文本?正文中替換詞中的所有答案僅適用于執行時頁面上的文本。
uj5u.com熱心網友回復:
事實證明,對于所謂的宣告性標記語言 HTML 而言,以高性能的方式執行上述操作并且不破壞任何內容是非常重要的。我在下面記錄了我在一個月的測驗和實驗中學到的東西。
為了對現有文本進行第一輪替換,我們將利用TreeWalker遍歷Text檔案中的每個節點并處理它們的內容。在這個例子中,我將用“h*ck”審查“heck”。
const callback = text => text.replaceAll(/heck/gi, 'h*ck');
function processNodes(root) {
const nodes = document.createTreeWalker(
root, NodeFilter.SHOW_TEXT, { acceptNode:
node => valid(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT
});
while (nodes.nextNode()) {
nodes.currentNode.nodeValue = callback(nodes.currentNode.nodeValue);
}
}
function valid(node) {
return (
node.parentNode !== null
&& node.parentNode.tagName !== 'SCRIPT'
&& node.parentNode.tagName !== 'STYLE'
&& !node.parentNode.isContentEditable
);
}
processNodes(document.body);
注意valid功能。這是為了處理三種特殊情況:
- 我們需要檢查父節點是否存在,因為有時當我們接近它時,節點會從檔案中洗掉
- 亂用
<script>和<style>標簽可能會破壞功能或演示 - 編輯
contenteditable元素會重置游標位置,這是一種糟糕的用戶體驗
但這只會處理頁面上已經存在的文本。為了觀察未來的變化,我們可以使用MutationObserver來觀察添加或修改的文本節點。
const IGNORED = [
Node.CDATA_SECTION_NODE,
Node.PROCESSING_INSTRUCTION_NODE,
Node.COMMENT_NODE,
];
const CONFIG = {subtree: true, childList: true, characterData: true};
const observer = new MutationObserver((mutations, observer) => {
observer.disconnect();
for (const mutation of mutations) {
const target = mutation.target;
switch (mutation.type) {
case 'childList':
for (const node of mutation.addedNodes) {
if (node.nodeType === Node.TEXT_NODE) {
if (valid(node)) {
node.nodeValue = callback(node.nodeValue);
}
} else if (!IGNORED.includes(node.nodeType)) {
processNodes(node);
}
}
break;
case 'characterData':
if (!IGNORED.includes(target.nodeType) && valid(target)) {
target.nodeValue = callback(target.nodeValue);
}
break;
}
}
observer.observe(document.body, CONFIG);
});
observer.observe(document.body, CONFIG);
觀察者的回呼由兩個主要部分組成:一個childList處理任何新子樹和文本節點的案例,以及一個characterData處理內容改變的文本節點的案例。在進行任何我們自己的編輯之前,我們必須關閉觀察者以避免觸發無限回圈。還要注意IGNORED陣列;這是必要的,因為某些節點位于Text界面下,但不是面向用戶的、用戶可見的內容。
Putting those two pieces together should be enough 98% percent of the time. However, there are still many special cases we didn't consider:
- Certain HTML attributes that get rendered as text (
placeholderin<input>,altin<img>,valuein<input type="button">) - CSS
contentproperty - Shadow DOMs
A proper explanation of workarounds for the above wouldn't fit in a StackOverflow answer, but I have written a free library called TextObserver that does it for you.
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/348952.html
標籤:javascript html css dom 突变观察者
