我正在尝试编写一个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(特别是Manipulation部分,包括DOM Insertion和General Attributes小节),但我没有看到任何有用的东西。
鉴于元素node
,我目前最好的想法是
lengthOfEndTag = node.tagName.length + 3;
lengthOfStartTag = node.outerHTML.length
- node.innerHTML.length
- lengthOfEndTag;
但当然我不想对结束标记做出这样的假设。
(最后,我熟悉正则表达式 - 但是如果可能的话,尽量避免使用它们。)
修改
@Pointy和@squint帮助我理解,例如,因为在创建DOM时HTML被丢弃,所以不可能看到</ p >
。没关系。调整后的目标是查找将在outerHTML
中呈现的开始和结束标记的长度。
答案 0 :(得分:1)
另一种方法是在节点的克隆副本上使用 XMLSerializer的 serializeToString
( id 设置)以避免必须解析 innerHTML ,然后拆分为"><"
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 将此转义为><
,因此不会更改.split
。
怎么没有关闭标签? close 将为null
。
答案 1 :(得分:0)
This answer帮助我了解@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;
}