我正在尝试创建一个文本搜索功能,但是当元素中有html时,我很难让它工作。这是一些简单的HTML来演示我的问题。
<b>
<input type="checkbox" value="" />
I need replaced
</b>
这是我目前正在使用javascript的地方。假设里面没有html,它的效果很好。
$("*", search_container).each(function() {
var replaceTxt = $(this).text().replace(new RegExp("(" + search_term + ")", 'i'), '<span style="color: #0095DA;" class="textSearchFound">$1</span>');
$(this).text().replaceWith(replaceTxt);
});
当用户输入时,我需要用span替换文本。因此,内容在他/她输入时应如下所示。
<b>
<input type="checkbox" value="" />
<span style="color: #0095DA" class="textSearchFound">I need</span> replaced
</b>
更新
在查看被投票重复的问题之后,我想出了这个。尽管可能很接近,但它会将html作为我不想要的文本插入DOM。请投票重新开启。
$("*", search_container).each(function() {
var node = $(this).get(0);
var childs = node.childNodes;
for(var inc = 0; inc < childs.length; inc++) {
//Text node
if(childs[inc].nodeType == 3){
if(childs[inc].textContent) {
childs[inc].textContent = childs[inc].textContent.replace(new RegExp("(" + search_term + ")", 'i'), '<span style="color: #0095DA;" class="textSearchFound">$1</span>');
}
//IE
else {
childs[inc].nodeValue = childs[inc].nodeValue.replace(new RegExp("(" + search_term + ")", 'i'), '<span style="color: #0095DA;" class="textSearchFound">$1</span>');
}
}
}
});
答案 0 :(得分:6)
它并不漂亮,但最好的方法是以递归方式遍历页面上的每个节点。当您遇到文本节点时,请检查它是否包含您的搜索字符串。如果找到它,请删除原始文本节点,并将其替换为匹配前文本的文本节点,带有突出显示匹配的新元素,以及匹配后文本节点。
这是一个示例函数:
var highlightSomeText = function(needle, node){
node = node || document.body; // initialize the first node, start at the body
if(node.nodeName == 'SCRIPT') return; // don't mess with script tags
if(node.nodeType == 3){ // if node type is text, search for our needle
var parts = node.nodeValue.split(needle); // split text by our needle
if(parts.length > 1){ // if we found our needle
var parent = node.parentNode
for(var i = 0, l = parts.length; i < l;){
var newText = document.createTextNode(parts[i++]); // create a new text node, increment i
parent.insertBefore(newText, node);
if(i != l){ // if we're not on the last part, insert a new span element for our highlighted text
var newSpan = document.createElement('span');
newSpan.className = 'textSearchFound';
newSpan.style.color = '#0095DA';
newSpan.innerHTML = needle;
parent.insertBefore(newSpan, node);
}
}
parent.removeChild(node); // delete the original text node
}
}
for(var i = node.childNodes.length; i--;) // loop through all child nodes
highlightSomeText(needle, node.childNodes[i]);
};
highlightSomeText('I need');
关于jsfiddle的演示:http://jsfiddle.net/8Mpqe/
编辑: 以下是使用Regexp不区分大小写的更新方法:http://jsfiddle.net/RPuRG/
更新了行:
var parts = node.nodeValue.split(new RegExp('(' + needle + ')','i'));
使用包含在捕获组()
中的正则表达式,捕获的结果将被拼接到部件数组中。
newSpan.innerHTML = parts[i++];
新span元素的文本将是我们数组中的下一部分。
编辑2:由于在某些文本字段的每个键盘事件上都会调用此函数,因此提问者希望在每次运行之前删除突出显示的span标记。为此,需要打开每个突出显示的元素,然后在父节点上调用normalize
以将相邻的文本节点重新合并在一起。这是一个jQuery示例:
$('.textSearchFound').each(function(i, el){
$(el).contents().unwrap().
parent()[0].normalize();
});
这是完成的工作演示:http://jsfiddle.net/xrL3F/
答案 1 :(得分:1)
您可以使用JQuery .contents()
方法获取元素的子节点。文本节点将具有nodeType == 3
。然后,您可以使用其textContent
属性获取文本节点的文本。
var getNonEmptyChildTextNodes = function($element) {
return $element.contents().filter(function() {
return (this.nodeType == 3) && (this.textContent.trim() != '');
});
};
var $textNode = getNonEmptyChildTextNodes($('b')).first(),
text = $textNode[0].textContent;
然后执行替换,您可以执行以下操作:
var search_term = 'I need',
regExp = new RegExp(search_term, 'gi');
var result = regExp.exec(text);
if (result !== null) {
var $elements = $(),
startIndex = 0;
while (result !== null) {
$elements = $elements.add(document.createTextNode(text.slice(startIndex, result.index)));
$elements = $elements.add('<span style="color: #0095DA;" class="textSearchFound">' + result[0] + '</span>');
startIndex = regExp.lastIndex;
result = regExp.exec(text);
}
$elements = $elements.add(document.createTextNode(text.slice(startIndex)));
$textNode.replaceWith($elements);
}
这是一个显示完整搜索的jsfiddle&amp;使用上面的代码换行。