使用包含html的文本替换元素内的文本,而不删除已存在的html

时间:2014-03-10 16:00:47

标签: javascript jquery

我正在尝试创建一个文本搜索功能,但是当元素中有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>');
            }
        }
    }
});

2 个答案:

答案 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


这是一个显示完整搜索的jsfiddle&amp;使用上面的代码换行。