Заменить содержимое в элементах без замены HTML
Предположим, у меня есть следующая структура 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.
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>
Вы можете избежать 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>
Похоже, вы хотите выделить все символы T, но ваше регулярное выражение также ловит ваш HTML.
Выполните операцию для innerText, а не innerHTML. Я не использовал jQuery в течение нескольких лет, так что может быть более оптимальный способ сделать это, но это должно сделать это.
$("test *").each(function(index, value) {
$(this)[0].innerText = $(this)[0].innerText.replace(new RegExp('t', "ig"), "<b>t</b>");
});