如何在不破坏现有 HTML 的情况下更改 DOM 中的所有文本?
How to change all texts in DOM without breaking existing HTML?
我想用 javascript 替换页面上的特定文本。为简单起见,假设我想用字母 X 替换所有字母 A。重要的是它不会中断内联 HTML.
是否有一种简单的方法来遍历所有 DOM 元素并仅更改实际文本?
<span>hello world <a href="/">abcd</a>..</span>
应该变成
<span>hello world <a href="/">xbcd</a>..</span>
而不是
<spxn>hello world <x href="/">xbcd</x>..</spxn>
迭代 all text nodes,如果它们包含 a
:
,则更改它们的 nodeValue
function getAllTextNodes() {
var walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_TEXT,
null,
false
);
var node;
var textNodes = [];
while(node = walker.nextNode()) {
textNodes.push(node);
}
return textNodes;
}
getAllTextNodes().forEach((node) => {
const { nodeValue } = node;
const newValue = nodeValue.replace(/a/g, 'x');
if (newValue !== nodeValue) {
node.nodeValue = newValue;
}
});
<a href="/">abcd</a>
您还可以创建parents的白名单或黑名单,其文本节点可更改,如果您愿意:
function getAllTextNodes() {
var walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_TEXT,
null,
false
);
var node;
var textNodes = [];
while(node = walker.nextNode()) {
textNodes.push(node);
}
return textNodes;
}
const tagNamesToKeepUnchanged = ['SCRIPT'];
getAllTextNodes().forEach((node) => {
if (tagNamesToKeepUnchanged.includes(node.parentNode.tagName)) {
return;
}
const { nodeValue } = node;
const newValue = nodeValue.replace(/a/g, 'x');
if (newValue !== nodeValue) {
node.nodeValue = newValue;
}
});
const obj = JSON.parse(
document.querySelector('script[type="application/json"]').textContent
);
console.log(obj.key);
<a href="/">abcd</a>
<p>foo bar</p>
<script type="application/json">{"key":"value"}</script>
这将保留标签名称、事件侦听器以及除了某些文本节点的内容之外的几乎所有内容。
我经常用这个:
/**
* Executes operation over all text nodes in a document
* @param {HTMLElement} element
* @param {function(Text):void} callback
*/
function processTextNodes(element, callback) {
// For text node, execute callback
if (element.nodeType == Node.TEXT_NODE)
callback(element);
// Otherwise, loop over child nodes
else if (element.childNodes.length > 0) {
for (const childNode of element.childNodes) {
if (childNode.nodeType == Node.TEXT_NODE)
callback(childNode);
// Recursion to child nodes
else {
processTextNodes(childNode, callback);
}
}
}
}
例如试试这个:
processTextNodes(document.body, (el)=>{el.data = el.data.toUpperCase()})
我在几个用户脚本中使用了它来替换新闻文章中的单词,使它们更有趣。
我想用 javascript 替换页面上的特定文本。为简单起见,假设我想用字母 X 替换所有字母 A。重要的是它不会中断内联 HTML.
是否有一种简单的方法来遍历所有 DOM 元素并仅更改实际文本?
<span>hello world <a href="/">abcd</a>..</span>
应该变成
<span>hello world <a href="/">xbcd</a>..</span>
而不是
<spxn>hello world <x href="/">xbcd</x>..</spxn>
迭代 all text nodes,如果它们包含 a
:
nodeValue
function getAllTextNodes() {
var walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_TEXT,
null,
false
);
var node;
var textNodes = [];
while(node = walker.nextNode()) {
textNodes.push(node);
}
return textNodes;
}
getAllTextNodes().forEach((node) => {
const { nodeValue } = node;
const newValue = nodeValue.replace(/a/g, 'x');
if (newValue !== nodeValue) {
node.nodeValue = newValue;
}
});
<a href="/">abcd</a>
您还可以创建parents的白名单或黑名单,其文本节点可更改,如果您愿意:
function getAllTextNodes() {
var walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_TEXT,
null,
false
);
var node;
var textNodes = [];
while(node = walker.nextNode()) {
textNodes.push(node);
}
return textNodes;
}
const tagNamesToKeepUnchanged = ['SCRIPT'];
getAllTextNodes().forEach((node) => {
if (tagNamesToKeepUnchanged.includes(node.parentNode.tagName)) {
return;
}
const { nodeValue } = node;
const newValue = nodeValue.replace(/a/g, 'x');
if (newValue !== nodeValue) {
node.nodeValue = newValue;
}
});
const obj = JSON.parse(
document.querySelector('script[type="application/json"]').textContent
);
console.log(obj.key);
<a href="/">abcd</a>
<p>foo bar</p>
<script type="application/json">{"key":"value"}</script>
这将保留标签名称、事件侦听器以及除了某些文本节点的内容之外的几乎所有内容。
我经常用这个:
/**
* Executes operation over all text nodes in a document
* @param {HTMLElement} element
* @param {function(Text):void} callback
*/
function processTextNodes(element, callback) {
// For text node, execute callback
if (element.nodeType == Node.TEXT_NODE)
callback(element);
// Otherwise, loop over child nodes
else if (element.childNodes.length > 0) {
for (const childNode of element.childNodes) {
if (childNode.nodeType == Node.TEXT_NODE)
callback(childNode);
// Recursion to child nodes
else {
processTextNodes(childNode, callback);
}
}
}
}
例如试试这个:
processTextNodes(document.body, (el)=>{el.data = el.data.toUpperCase()})
我在几个用户脚本中使用了它来替换新闻文章中的单词,使它们更有趣。