5

假设我有一个看起来像这样的 HTML 页面:

<html><body>
00123
<input value="00123">
00456
</body></html>

我想使用 javascript/jQuery 让它看起来像这样:

<html><body>
<a href="#00123">00123</a>
<input value="00123">
<a href="#00456">00456</a>
</body></html>

本质上,我想用 HTML 锚标记将正则表达式匹配的纯字符串包装在文档中。在这个例子中,我想做一些类似的事情:

$('body').html($('body').html().replace(/(00\d+)/, '<a href="#$1">$1</a>'));

请参阅带有此示例的 jsFiddle:http: //jsfiddle.net/NATnr/2/

这个解决方案的问题是input元素内的文本被匹配和替换。

有谁知道如何使用 javascript/jQuery 以这种方式仅匹配和替换文档中的纯文本?

4

4 回答 4

8

尝试按nodeType过滤body'scontents()以仅获取文本节点,然后用 jQuery 生成的锚元素替换它们(这些节点中的任何额外文本都将保留为文本节点):

$('body').contents().filter(function() {
    return this.nodeType === 3;
}).each(function() {
    $(this).replaceWith($(this).text().replace(/(00\d+)/g, '<a href="#$1">$1</a>'));
});

小提琴

如您所知,通常使用 Regex 解析 HTML 不是一个好主意(注意ponies,它们是邪恶的),但是如果您将要解析的 HTML 的一部分隔离出来并且它遵循相对简单的模式,它是一个可行的选择。

编辑:在您的正则表达式中包含g标志(全局修饰符)以允许在单个文本节点内匹配多个锚点。

于 2012-07-26T02:35:47.637 回答
6

最终的解决方案最终看起来像这样:

jQuery.fn.linker = function () {
    $(this).contents()
        .filter(function() { return this.nodeType != Node.TEXT_NODE; })
        .each(function () { $(this).linker(); });
    $(this).contents()
        .filter(function() { return this.nodeType == Node.TEXT_NODE; })
        .each(function () {
            $(this).replaceWith(
                $(this).text().replace(/(00\d+)/g, '<a href="#$1">$1</a>')
            );
        });
}
$(document).ready(function () {
    $('body').linker();
});

在此处查看 jsFiddle:http: //jsfiddle.net/fr4AL/4/

谢谢:

于 2012-07-26T03:54:42.877 回答
0

这来自bobince对问题的相关回答:

你不想用正则表达式处理 HTML 是对的。分配大量 .html(); 也是一个坏消息;除了序列化和重新解析大量 HTML 的性能缺陷之外,您还会丢失不可序列化的数据,例如事件侦听器、表单数据和 JS 属性/引用。

这是一个简单的 JavaScript/DOM,它允许匹配 RegExp 模式。jQuery 在这里并没有真正给你太多帮助,因为选择器只能选择元素,而 ':contains' 选择器是递归的,所以对我们来说不太有用。

// Find text in descendents of an element, in reverse document order
// pattern must be a regexp with global flag
//
function findText(element, pattern, callback) {
    for (var childi= element.childNodes.length; childi-->0;) {
        var child= element.childNodes[childi];
        if (child.nodeType==1) {
            findText(child, pattern, callback);
        } else if (child.nodeType==3) {
            var matches= [];
            var match;
            while (match= pattern.exec(child.data))
                matches.push(match);
            for (var i= matches.length; i-->0;)
                callback.call(window, child, matches[i]);
        }
    }
}

findText(document.body, /\bBuyNow\b/g, function(node, match) {
    var span= document.createElement('span');
    span.className= 'highlight';
    node.splitText(match.index+6);
    span.appendChild(node.splitText(match.index+3));
    node.parentNode.insertBefore(span, node.nextSibling);
});
于 2012-07-26T02:31:19.457 回答
0

试一试……干净多了!;)

$('input').each(function() {
    var temp;
       temp = $(this).val();
       $(this).before('<a href="#' + temp +'">' +temp+ '</a>');
});
$('body').contents().filter(function() {return this.nodeType == 3;}).remove();
于 2012-07-26T02:41:30.237 回答