将textNode替换为混合内容的HTML字符串

时间:2018-11-10 18:30:49

标签: javascript html dom

对于此HTML节点:

<div><i>foo</i> and <i>bar</i> go ### with <b>baz</b></div>

我想用另一个节点(###)替换字符串<u>well</u>,而不替换包装器innerHTML的整个div

预期结果:

<div><i>foo</i> and <i>bar</i> go <u>well</u> with <b>baz</b></div>

我的方法是迭代 childNodes ,仅过滤我要替换的字符串中的TEXT_NODE元素,然后使用DOM Fragment将这些textNode替换为replaceChild保留替换的内容:

var root = document.querySelector('div'),
    tag = "<u>well</u>",
    tempFrag = document.createDocumentFragment(),
    children = root.childNodes,
    replacedString;

 for( var i = children.length; i--; ){
      if( children[i].nodeType === Node.TEXT_NODE && 
          children[i].nodeValue.length > 1        && 
          children[i].nodeValue.indexOf('###') != -1 ){
       
            replacedString = children[i].nodeValue.replace('###', tag);

            console.log( replacedString );
            tempFrag.innerHTML = replacedString;
            children[i].parentNode.replaceChild(tempFrag, children[i])
      }    
}
<div><i>foo</i> and <i>bar</i> go ### with <b>baz</b></div>


如您所见,以这种方式替换textNode不能按预期工作。

虽然我可以手动提取 replacedString 的每个部分并将其分解为:

`before textNode` / New element / `after textNode` 

并将它们全部拼凑在一起,将创建大量代码(这实际上是我当前正在执行的方式,并且正在尝试考虑一种更智能的方式,但是该片段对解析和解析没有帮助。如您所见)

2 个答案:

答案 0 :(得分:1)

代替此:

replacedString = inputChildren[i].nodeValue.replace('###', tag);

您可以使用

var offset = ...indexOf('###');
replacementNode = textnode.splitText(offset); 

然后添加

textnode.parent.insertBefore(wrapper, replacementNode);

您可以实现自己想要的。

答案 1 :(得分:0)

var root = document.querySelector('div'),
    tag = document.createElement('u'),
    children = root.childNodes,
    replacedNode,
    idx;

 tag.innerHTML = "well";
 
 for( var i = children.length; i--; ){
      if( children[i].nodeType === Node.TEXT_NODE && 
          children[i].nodeValue.length > 1 ){
            idx = children[i].nodeValue.indexOf('###');
            if( idx == -1 ) continue;
            
            replacedNode = children[i].splitText(idx);
            // remove '###' from the second split textNode ('### with')
            replacedNode.nodeValue = replacedNode.nodeValue.replace('###', '');
            // put the tag element before the second split textNode
            children[i].parentNode.insertBefore(tag, replacedNode);
      }    
}
<div><i>foo</i> and <i>bar</i> go ### with <b>baz</b></div>