4

我正在尝试编写一个 jQuery 或纯 Javascript 函数(首选更具可读性的解决方案),它可以计算 HTML 文档中开始标记或结束标记的长度。

例如,

<p>Hello.</p>

将返回 3 和 4 作为开始和结束标签长度。添加属性,

<span class="red">Warning!</span>

将返回 18 和 7 作为开始和结束标签的长度。最后,

<img src="foobar.png"/>

将返回 23 和 0(或 -1)作为开始和结束标签长度。

我正在寻找一个规范的、保证工作符合规范的解决方案,因此我尝试使用 DOM 方法而不是手动文本操作。例如,我希望该解决方案即使适用于奇怪的情况,例如

<p>spaces infiltrating the ending tag</ p >

<img alt="unended singleton tags" src="foobar.png">

等等。也就是说,我的希望是,只要我们使用正确的 DOM 方法,无论事情变得多么奇怪,我们都应该能够找到和之间的字符数,<甚至>

<div data-tag="<div>">HTML-like strings within attributes</div>

我查看了 jQuery API(尤其是操作部分,包括 DOM 插入和常规属性小节),但我没有看到任何有用的信息。

目前我最好的想法,给定一个元素node

lengthOfEndTag = node.tagName.length + 3;

lengthOfStartTag = node.outerHTML.length
                 - node.innerHTML.length
                 - lengthOfEndTag;

但我当然不想对结束标签做出这样的假设。

(最后,我熟悉正则表达式——但尽可能避免使用它们。)


编辑

</ p >@Pointy 和 @squint 帮助我理解,例如,因为一旦创建 DOM,HTML 就会被丢弃,所以无法看到。没关系。调整后的目标是找到开始和结束标签的长度,outerHTML.

4

2 回答 2

1

另一种方法是在节点的克隆副本(带有id集)上使用XMLSerializer ,以避免必须解析innerHTML,然后拆分serializeToString"><"

var tags = (function () {
    var x = new XMLSerializer(); // scope this so it doesn't need to be remade
    return function tags(elm) {
        var s, a, id, n, o = {open: null, close: null}; // spell stuff with var
        if (elm.nodeType !== 1) throw new TypeError('Expected HTMLElement');
        n = elm.cloneNode(); // clone to get rid of innerHTML
        id = elm.getAttribute('id'); // re-apply id for clone
        if (id !== null) n.setAttribute('id', id); // if it was set
        s = x.serializeToString(n); // serialise
        a = s.split('><');
        if (a.length > 1) { // has close tag
            o.close = '<' + a.pop();
            o.open = a.join('><') + '>'; // join "just in case"
        }
        else o.open = a[0]; // no close tag
        return o;
    }
}()); // self invoke to init

.length运行后,您可以访问打开关闭属性

tags(document.body); // {open: "<body class="question-page">", close: "</body>"}

如果属性的值包含><在其中怎么办?XMLSerializer将其转义为,&gt;&lt;因此它不会更改.split.
没有关闭标签怎么办?关闭null

于 2013-05-03T21:50:59.250 回答
0

这个答案帮助我理解了@Pointy 和@squint 想要表达的意思。

以下解决方案对我有用:

$.fn.lengthOfStartTag = function () {
    var node = this[0];
    if (!node || node.nodeType != 1) {
        $.error("Called $.fn.lengthOfStartTag on non-element node.");
    }
    if (!$(node).is(":empty")) {
        return node.outerHTML.indexOf(node.innerHTML);
    }
    return node.outerHTML.length;
}

$.fn.lengthOfEndTag = function () {
    var node = this[0];
    if (!node || node.nodeType != 1) {
        $.error("Called $.fn.lengthOfEndTag on non-element node.");
    }
    if (!$(node).is(":empty")) {
        var indexOfInnerHTML = node.outerHTML.indexOf(node.innerHTML);
        return node.outerHTML.length - (indexOfInnerHTML + node.innerHTML.length);
    }
    return -1;
}

示例 jsFiddle 在这里。

于 2013-05-03T20:44:30.567 回答