在不替换HTML的情况下替换元素中的内容

7
假设我有以下HTML结构:
<test>
    <div>
        This is a test
        </div>
    <div>
        This is another test
        <button>
            Button test
        </button>
    </div>
</test>

现在我使用以下jQuery代码来替换,例如,“T”:
$("test *").each(function(index, value) {
    $(this).html($(this).html().replace(new RegExp('t', "ig"), "<b>t</b>"));
});

然而,这会导致以下 HTML 结构(这是意外的,注意 <button> 标签破坏了我的 HTML):
<test>
    <div>
        <b>T</b>his is a <b>t</b>es<b>t</b>
        </div>
    <div>
        <b>T</b>his is ano<b>t</b>her <b>t</b>es<b>t</b>
        <bu<b>t</b><b>t</b>on>
            Bu<b>t</b><b>t</b>on <b>t</b>es<b>t</b>
            </bu<b>t</b><b>t</b>on>
        </div>
    </test>

我想要实现的是:
<test>
    <div>
        <b>T</b>his is a <b>t</b>es<b>t</b>
        </div>
    <div>
        <b>T</b>his is ano<b>t</b>her <b>t</b>es<b>t</b>
        <button>
            Bu<b>t</b><b>t</b>on <b>t</b>es<b>t</b>
            </button>
        </div>
    </test>

基本上,我想在整个元素内进行替换,但保留HTML标记和所有HTML属性。

1
所以如果我理解正确,您不希望<button>变成<bu<b>t</b><b>t</b>on>,这是主要问题,对吗? - Goose
@Goose,对的,但这当然不仅适用于button标签,而是适用于所有与正则表达式匹配的HTML标签。 - TVA van Hesteren
3个回答

3

使用jQuery可以很简单地实现这一点。创建一个函数,该函数接受您希望更新文本的元素、您希望替换的文本以及您希望用其替换的内容。然后在函数中,您需要删除子HTML,并使用替换文本更新元素中剩余的任何文本。然后您可以递归运行此相同的函数,以便为每个子元素执行相同的操作,然后将它们附加回父元素。

function replaceTextInHtmlBlock($element, replaceText, replaceWith)
{
  var $children = $element.children().detach();
  //Now that there should only be text nodes left do your replacement
  $element.html($element.text().replace(replaceText, replaceWith));
  //Run this function for each child element
  $children.each(function(index, me){
    replaceTextInHtmlBlock($(me), replaceText, replaceWith);
  });
  $element.append($children);
}

$(document).ready(function(){
  $("#doReplace").click(function(){
    replaceTextInHtmlBlock($("#top"), $("#replace").val(), $("#with").val());
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="top">
  <div>
    This is a test
  </div>
  <div>
    This is another test
    <button>
            Button test
            </button>
  </div>
</div>
<br />
<br />
<div>
  <label>Replace</label>
  <input id="replace" value="t" />
  <label>with</label>
  <input id="with" value="<strong>t</strong>" />
  <button id="doReplace">Do Replace</button>
</div>


0

您可以避免使用jQuery,而不必担心button(因为如果您碰到input标签等,这并没有帮助),只需替换文本节点即可。

我们查找文本节点,在每种情况下发现我们看到的第一个“t”(或“T”),将其包装在<b>中,并继续前进。同一区域中的其他匹配项将在后续文本节点中找到。

var wrapText = "t";

var el = document.getElementsByTagName('test')[0];

replaceIn(el);

function replaceIn(el) {
  var i = 0;

  while (i < el.childNodes.length) {
    var cn = el.childNodes[i];

    if (cn.nodeType == 3) {   // text node
      var p = cn.textContent.toLowerCase().indexOf(wrapText);

      if (p >= 0) {
        var range = new Range();
        range.setStart(cn, p);
        range.setEnd(cn, p + 1);
        range.surroundContents(document.createElement('b'));
        ++i;   // don't check the <b> we just created
      }
    } 
    else {
      replaceIn(cn);
    }

    ++i;
  }
}
<test>
  <div>
    This is a test
  </div>
  <div>
    This is another test
    <button>
      Button test
   </button>

    <input value="input test" />
  </div>
</test>


谢谢您的回复。它很好用,但是我必须处理整个页面,这非常慢。当我执行搜索时,网页几乎会崩溃。 - TVA van Hesteren
如果你不想处理标签,那么你必须处理单独的文本节点而不仅仅是字符串。老实说,我认为事后没有高效的解决方案。 - Goose

0

看起来你想将所有的T字符加粗,但是你的正则表达式也匹配了你的HTML。

在innerText上执行操作而不是innerHTML。我已经好几年没有使用过jQuery了,所以可能有更优化的方法,但这应该可以。

$("test *").each(function(index, value) {
    $(this)[0].innerText = $(this)[0].innerText.replace(new RegExp('t', "ig"), "<b>t</b>");
});

谢谢您的回答,但是这样做会将所有子元素从父元素中移除,对吗?如果是这样的话,那就是不希望的行为。 - TVA van Hesteren
我刚刚测试了你的代码,它完全没有保留我的HTML。不过还是谢谢你分享你的想法。 - TVA van Hesteren

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