使用JavaScript将HTML插入文本节点
我有一个小文本节点:使用JavaScript将HTML插入文本节点,javascript,dom,textnode,Javascript,Dom,Textnode,我有一个小文本节点: var node 我想在“lol”的每一次出现的时候都画上一个句号 node.nodeValue=node.nodeValue.replace(/lol/,“lol”) 当我想要“lol”作为span元素时,它会打印出“lol”。下面的文章提供了用HTML元素替换文本的代码: 从文章中: var matchText = function(node, regex, callback, excludeElements) { excludeElements ||
var node
我想在“lol”的每一次出现的时候都画上一个句号
node.nodeValue=node.nodeValue.replace(/lol/,“lol”)
当我想要
“lol”
作为span元素时,它会打印出“lol”
。下面的文章提供了用HTML元素替换文本的代码:
从文章中:
var matchText = function(node, regex, callback, excludeElements) {
excludeElements || (excludeElements = ['script', 'style', 'iframe', 'canvas']);
var child = node.firstChild;
do {
switch (child.nodeType) {
case 1:
if (excludeElements.indexOf(child.tagName.toLowerCase()) > -1) {
continue;
}
matchText(child, regex, callback, excludeElements);
break;
case 3:
child.data.replace(regex, function(all) {
var args = [].slice.call(arguments),
offset = args[args.length - 2],
newTextNode = child.splitText(offset);
newTextNode.data = newTextNode.data.substr(all.length);
callback.apply(window, [child].concat(args));
child = newTextNode;
});
break;
}
} while (child = child.nextSibling);
return node;
}
用法:
matchText(document.getElementsByTagName("article")[0], new RegExp("\\b" + searchTerm + "\\b", "g"), function(node, match, offset) {
var span = document.createElement("span");
span.className = "search-term";
span.textContent = match;
node.parentNode.insertBefore(span, node.nextSibling);
});
matchText(document.getElementsByTagName("article")[0], new RegExp("\\b" + searchTerm + "\\b", "g"), function(node, match, offset) {
var span = document.createElement("span");
span.className = "search-term";
span.textContent = match;
return span;
});
解释如下:
基本上,正确的方法是
您可能需要
节点
作为父节点,这样您就可以使用innerHTML:
node.innerHTML=node.childNodes[0].nodeValue.replace(/lol/, "<span>lol</span>");
node.innerHTML=node.childNodes[0].nodeValue.replace(/lol/,“lol”);
这里的
node.childNodes[0]
指的是实际的文本节点,node
是它的包含元素。Andreas Josas给出的答案很好。但是,当搜索词在同一文本节点中出现多次时,代码有几个错误。以下是修复这些错误的解决方案,此外,插入内容被分解为matchText,以便于使用和理解。现在,回调中只构造了新标记,并通过返回将其传递回matchText
更新了matchText函数并修复了错误:
var matchText = function(node, regex, callback, excludeElements) {
excludeElements || (excludeElements = ['script', 'style', 'iframe', 'canvas']);
var child = node.firstChild;
while (child) {
switch (child.nodeType) {
case 1:
if (excludeElements.indexOf(child.tagName.toLowerCase()) > -1)
break;
matchText(child, regex, callback, excludeElements);
break;
case 3:
var bk = 0;
child.data.replace(regex, function(all) {
var args = [].slice.call(arguments),
offset = args[args.length - 2],
newTextNode = child.splitText(offset+bk), tag;
bk -= child.data.length + all.length;
newTextNode.data = newTextNode.data.substr(all.length);
tag = callback.apply(window, [child].concat(args));
child.parentNode.insertBefore(tag, newTextNode);
child = newTextNode;
});
regex.lastIndex = 0;
break;
}
child = child.nextSibling;
}
return node;
};
用法:
matchText(document.getElementsByTagName("article")[0], new RegExp("\\b" + searchTerm + "\\b", "g"), function(node, match, offset) {
var span = document.createElement("span");
span.className = "search-term";
span.textContent = match;
node.parentNode.insertBefore(span, node.nextSibling);
});
matchText(document.getElementsByTagName("article")[0], new RegExp("\\b" + searchTerm + "\\b", "g"), function(node, match, offset) {
var span = document.createElement("span");
span.className = "search-term";
span.textContent = match;
return span;
});
如果您希望插入锚定(链接)标记而不是span标记,请将create元素更改为“a”而不是“span”,添加一行以将href属性添加到标记,并将“a”添加到excludeElements列表中,以便不会在链接中创建链接。并不是说这是一个更好的答案,但我正在发布我为完整性所做的事情。在我的例子中,我已经查找或确定了需要在特定的#文本节点中高亮显示的文本的偏移量。这也澄清了步骤
//node is a #text node, startIndex is the beginning location of the text to highlight, and endIndex is the index of the character just after the text to highlight
var parentNode = node.parentNode;
// break the node text into 3 parts: part1 - before the selected text, part2- the text to highlight, and part3 - the text after the highlight
var s = node.nodeValue;
// get the text before the highlight
var part1 = s.substring(0, startIndex);
// get the text that will be highlighted
var part2 = s.substring(startIndex, endIndex);
// get the part after the highlight
var part3 = s.substring(endIndex);
// replace the text node with the new nodes
var textNode = document.createTextNode(part1);
parentNode.replaceChild(textNode, node);
// create a span node and add it to the parent immediately after the first text node
var spanNode = document.createElement("span");
spanNode.className = "HighlightedText";
parentNode.insertBefore(spanNode, textNode.nextSibling);
// create a text node for the highlighted text and add it to the span node
textNode = document.createTextNode(part2);
spanNode.appendChild(textNode);
// create a text node for the text after the highlight and add it after the span node
textNode = document.createTextNode(part3);
parentNode.insertBefore(textNode, spanNode.nextSibling);
对于那些现在发现这个问题的人,最新的答案如下:
function textNodeInnerHTML(textNode,innerHTML) {
var div = document.createElement('div');
textNode.parentNode.insertBefore(div,textNode);
div.insertAdjacentHTML('afterend',innerHTML);
div.remove();
textNode.remove();
}
其思想是在textNode
之前插入一个新创建的html元素(比如var div=document.createElement('div');
),方法是:
textNode.parentNode.insertBefore(div,textNode);
textNode.remove();
div.remove();
然后使用:
div.insertAdjacentHTML(
'afterend',
textNode.data.replace(/lol/g,`<span style="color : red">lol</span>`)
)
[...elm.querySelectorAll('*')]
.map(l => [...l.childNodes])
.flat()
.filter(l => l.nodeType === 3);
insertAdjacentHTML
不会像innerHTML
那样销毁事件侦听器
如果要查找属于elm
后代的所有文本节点,请使用:
div.insertAdjacentHTML(
'afterend',
textNode.data.replace(/lol/g,`<span style="color : red">lol</span>`)
)
[...elm.querySelectorAll('*')]
.map(l => [...l.childNodes])
.flat()
.filter(l => l.nodeType === 3);
在这种情况下,您必须使用html重新定位文本节点content@ArunPJohny我该怎么做?@JacksonGariety您需要用新的domspan元素和文本节点替换文本节点,或者修改其父节点的innerHTML属性。试一试,发布您尝试的内容。@ArunPJohny文本节点没有innerHTMl属性。@JacksonGariety您不能这样设置它,您可能需要更正一些代码来替换文本节点。您可以共享文本节点的html吗?B警告:替换包含节点的innerHTML会破坏可能已通过脚本添加事件侦听器的子节点。这对我不起作用(Chrome 50);没有视觉变化。我可以在控制台中看到,
node.innerHTML
已更改,但UI没有更改。另外,node.parentNode.innerHTML
不包含新的更改。如果parent.node=body,可能有很多同级,那么您如何知道要替换哪个子级呢?对于未来的读者来说,还有一个重要的问题-这个答案是将文本内容转换为html。如果文本内容中碰巧有html标记,那么它们将不会被转义,充其量这将产生意外的结果,最坏的情况下这可能是一个安全风险。我添加了一个补丁regex.lastIndex=0
,以在重用regex时重置它。请您在有机会时澄清文本和替换发生的位置添加(此处放置文本)放置(此处放置替换文本)searchTerm
是您正在搜索的文本。您提供的回调将接收dom节点、找到的匹配项以及找到的内容的偏移量。然后,你可以在回调中使用这些知识做任何你想做的事情,比如替换它、给节点上色、拆分文本并在其周围放置标记,或者做任何你想做的事情,现在你已经知道在dom中找到搜索词的确切位置了。谢谢你,这是对我最好的答案。你如何将这些用于数字?你能举一个查找和替换数字的例子吗。例如,将不正确的邮政编码替换为邮政编码。数字,但正如您所看到的,这是针对文本的,我仍在尝试找出替换数字。当您有机会时,请您澄清文本和替换发生在何处添加(此处放置文本)放置(此处放置替换文本)这是文本节点内多个匹配的问题:如果(child==null)返回,则应添加if
aftervar child=node.firstChild代码>。