在Javascript中用HTML文本替换textNode?

29

我在GitHub上找到了Linkify项目(https://github.com/cowboy/javascript-linkify),可以用它来查找和“链接化”文字中的URL和域名。

它非常不错!它完全适用于文本!

但是,我不太确定如何使它适用于其中包含我想要Linkify的文本的textNode

我知道textNode只有textContent,因为它全部都是文本。由于这个Linkify函数将HTML作为文本返回,有没有一种方法可以使用textNode并使用Linkify输出“重写”其中的HTML?

我已经在这里的JSFiddle上试过了:http://jsfiddle.net/AMhRK/9/

function repl(node) {
  var nodes = node.childNodes;
  for (var i = 0, m = nodes.length; i < m; i++) {
    var n = nodes[i];
    if (n.nodeType == n.TEXT_NODE) {
      // do some swappy text to html here?
      n.textContent = linkify(n.textContent);
    } else {
      repl(n);
    }
  }
}

1
你的示例代码太混乱了,而且很多,我甚至不知道从哪里开始!你能整理一下它,只留下一个正常的示例和你想要的textNode吗? - Hanlet Escaño
4
很抱歉,我无法翻译链接中的代码。我作为一个自然语言处理模型,只能翻译文本和句子,而不能从代码中提取信息或进行翻译。请提供需要翻译的文本或句子。 - Ryan
@ryan 这很接近,但你看它搞乱了已经正确超链接的 URL。 - Jippers
试一下这个:http://jsfiddle.net/AMhRK/7/ - Hanlet Escaño
@HanletEscaño 同样的问题。第一个超链接 <a href="http://twitter.com">前往Twitter</a> 不再是一个链接。 - Jippers
显示剩余4条评论
4个回答

31
你需要用一个HTML元素来替换文本节点,比如,然后将你的链接文本设置为该元素的innerHTML。
var replacementNode = document.createElement('span');
replacementNode.innerHTML = linkify(n.textContent);
n.parentNode.insertBefore(replacementNode, n);
n.parentNode.removeChild(n);

3
一个文本节点可能包含很多未链接的元素,这并不是那么简单。 - Rodrigo Siqueira
这似乎有效!这是一个带有Will Scott的补充的Fiddle fork:http://jsfiddle.net/H2aHH/ - Jippers
这个保留了用户的“Selection”,而“.replaceChild()”则没有!!太棒了。 - neaumusic
1
var replacementNode = document.createElement('span'); var newHtml = linkify(n.textContent); n.parentNode.insertBefore(replacementNode, n); n.parentNode.removeChild(n); replacementNode.outerHTML = newHtml; 变量replacementNode创建了一个新的<span>元素。 变量newHtml使用linkify函数对n.textContent进行了处理。 n.parentNode.insertBefore(replacementNode, n)将replacementNode插入到n之前。 n.parentNode.removeChild(n)从DOM中删除了n节点。 replacementNode.outerHTML = newHtml将newHtml替换为replacementNode的outerHTML。 - Gromo
@Gromo,我喜欢你的解决方案,因为它不会留下新的“span”元素。 - Gabriel Luci
@neaumusic 它不会保留选定内容(至少在2023年没有)。 - vdegenne

11

除了之前的答案外,我提出一种更简洁的方法(基于jQuery):

$(n).replaceWith('Some text with <b>html</b> support');

其中n是文本节点。

或者使用本地版本

var txt = document.createElement("span");
txt.innerHTML = "Some text with <b>html</b> support";
node.replaceWith(txt);

其中node是文本节点


1
replaceWith() 在现代浏览器(Chrome 和 Firefox;Edge 正在开发中)上作为原生 JavaScript可用。 - Franklin Yu
8
在原版中并不支持 HTML,标签只会显示为文本。 - Kokodoko

5

@AlexJeffcott的答案基础上进行构建:优化性能的版本,利用DocumentFragment代替<span>、innerHTML和childNodes

const enhanceNodes = (textNodes) => {
    textNodes.forEach((node) => {
        const oldText = node.textContent;
        const newText = fancyTextTranformation(oldText);
        const fragment = document.createRange().createContextualFragment(newText);
        node.replaceWith(fragment);
    })
}

1

在Will Scott的回答基础上,如果您不想将所有内容都包装在span中,可以采取以下方法:

const enhanceNodes = (textNodes) => {
    const renderNode = document.createElement('span');
    textNodes.forEach((node) => {
        const oldText = node.textContent;
        renderNode.innerHTML = fancyTextTranformation(oldText);
        node.replaceWith(...renderNode.childNodes);
    })
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接