获取位于 </body> 和 </html> 之间的 HTML 评论内容的最可靠方法是什么?

What's the most reliable way to get the contents of an HTML comment located between </body> and </html>?

我正在尝试获取页面上最后 HTML 评论的内容 -- 它包含一些由 Web 应用程序服务器写入的会话信息。它写在 </html> 标签之前。在读完这个问题 (Selecting HTML Comments with jQuery) 后,我们想出了一些可行但不一致的方法:

var commentString = $("*").contents().filter(function(){
     return this.nodeType == 8 ? this.nodeValue.indexOf("Expected Comment Text") > -1: false;
})[0].nodeValue;

问题是,如果页面包含 iframe(来自不同的域),* 选择器将命中它,然后我们就会被跨源策略阻止。我们可以将此选择器更改为 $("body"),它似乎适用于大多数浏览器,但这似乎依赖于浏览器将注释移动到 body 节点内,我不相信这种情况会普遍存在。

如有必要,我们可以使用 jQuery 1.7.2(但没有插件),良好的浏览器支持 (IE < 9) 很重要。

在没有 jQuery "in reverse" 的情况下遍历 DOM 直到我们遇到 nodeType === 8 是否最好?这样,浏览器将评论节点作为 <html><body> 的子节点并不重要,只要它是文档节点树中的最后一条评论即可。这会是什么样子? (我的DOM-遍历符不行。)

你为什么不使用

$("*").not("iframe")

作为选择器,如果其余代码工作正常并且 iframe 是唯一导致问题的元素?

var commentString = $("*").not("iframe").contents().filter(function(){
     return this.nodeType == 8 ? this.nodeValue.indexOf("Expected Comment Text") > -1: false;
})[0].nodeValue;

如果您采用您正在尝试的那种解决方案,将会有相当多的开销。

通过制作一个简单的、可重复使用的函数来完成 DOM。

function walk(node, cb) {
  cb(node);

  if (node.childNodes) {
    for (var i = 0; i < node.childNodes.length; i++) {
      walk(node.childNodes[i], cb);
    }
  }
}

// And use it like this:

walk(document, function(node) {
  if (node.nodeType === 8) {
    // do something with comment
    alert(node.data);
  }
});
<div>
  foo
  <iframe src="http://www.linuxmint.com"></iframe>
  <!-- some comment -->
</div>

这种方式更加高效和灵活。


这是 walk 函数的另一个变体,它不使用计数器循环。

function walk(node, cb) {
  cb(node);

  if (node = node.firstChild) {
    do walk(node, cb);
    while (node = node.nextSibling)
  }
}

这样更短更清晰。


如果你正在寻找 return 单个节点,那么你可以让你的回调以及递归调用 return 一个值,然后 return 当值实际上是 returned.

根据您的评论,此版本倒退了 DOM。

function walk(node, cb) {
  var res = cb(node);
  if (res)
    return res;

  if (node = node.lastChild) {
    do if (res = walk(node, cb))
      return res;
    while (node = node.previousSibling)
  }
}

var result = walk(document, function(node) {
  if (node.nodeType === 8) {
    return node;
  }
});

if (result)
  alert(result.data);
<div>
  foo
  <!-- Some other comment -->
  <iframe src="http://www.linuxmint.com"></iframe>
  <!-- Success! - Expected Comment Text -->
</div>