是否可以通过JavaScript引用注释元素/块?

时间:2011-05-17 07:50:21

标签: javascript dom comments

这听起来有点疯狂,但我想知道是否有可能获得对comment元素的引用,以便我可以用JavaScript动态替换其他内容。

<html>
<head>
</head>
<body>
<div id="header"></div>
<div id="content"></div>
<!-- sidebar place holder: some id-->
</body>
</html>

在上面的页面中,我可以参考注释块并将其替换为本地存储中的某些内容吗?

我知道我可以有一个div占位符。只是想知道它是否适用于评论块。 感谢。

8 个答案:

答案 0 :(得分:25)

var findComments = function(el) {
    var arr = [];
    for(var i = 0; i < el.childNodes.length; i++) {
        var node = el.childNodes[i];
        if(node.nodeType === 8) {
            arr.push(node);
        } else {
            arr.push.apply(arr, findComments(node));
        }
    }
    return arr;
};

var commentNodes = findComments(document);

// whatever you were going to do with the comment...
console.log(commentNodes[0].nodeValue);

答案 1 :(得分:12)

似乎存在使用注释作为占位符的合法(性能)问题 - 例如,没有可以匹配注释节点的CSS选择器,因此您将无法使用注释来查询它们。 document.querySelectorAll(),这使得定位评论元素既复杂又缓慢。

我的问题是,是否有另一个我可以放置内联的元素,它没有任何可见的副作用?我看到有些人使用<meta>标记,但我调查了这一点,并在<body>中使用该标记是无效的标记。

所以我确定了<script>标签。

使用自定义type属性,因此它实际上不会作为脚本执行,并使用data-属性来处理初始化占位符的脚本所需的任何初始化数据。

例如:

<script type="placeholder/foo" data-stuff="whatevs"></script>

然后只需查询这些标签 - 例如:

document.querySelectorAll('script[type="placeholder/foo"]')

然后根据需要更换它们 - here's a plain DOM example

请注意,此示例中的placeholder不是任何已定义的“真实”内容 - 您应将其替换为例如vendor-name以确保您的type不会与任何“真实”相冲突。

答案 2 :(得分:9)

基于hyperrslug的答案,你可以通过使用堆栈而不是函数递归来加快速度。如此jsPerf所示,Windows上的Chrome 36上的函数递归慢了42%,IE8兼容模式下的IE11下降了71%。在边缘模式下,IE11的运行速度似乎慢了约20%,但在所有其他测试情况下运行速度更快。

function getComments(context) {
    var foundComments = [];
    var elementPath = [context];
    while (elementPath.length > 0) {
        var el = elementPath.pop();
        for (var i = 0; i < el.childNodes.length; i++) {
            var node = el.childNodes[i];
            if (node.nodeType === Node.COMMENT_NODE) {
                foundComments.push(node);
            } else {
                elementPath.push(node);
            }
        }
    }

    return foundComments;
}

或者在TypeScript中完成:

public static getComments(context: any): Comment[] {
    var foundComments = [];
    var elementPath = [context];
    while (elementPath.length > 0) {
        var el = elementPath.pop();
        for (var i = 0; i < el.childNodes.length; i++) {
            var node = el.childNodes[i];
            if (node.nodeType === Node.COMMENT_NODE) {
                foundComments.push(node);
            } else {
                elementPath.push(node);
            }
        }
    }

    return foundComments;
}

答案 3 :(得分:4)

如果您使用jQuery,则可以执行以下操作以获取所有注释节点

comments = $('*').contents().filter(function(){ return this.nodeType===8; })

如果您只想要正文的评论节点,请使用

comments = $('body').find('*').contents().filter(function(){
     return this.nodeType===8;
 })

如果您希望将注释字符串作为数组,则可以使用map

comment_strings = comments.map(function(){return this.nodeValue;})

答案 4 :(得分:3)

有一个用于文档节点遍历的API:Document#createNodeIterator()

&#13;
&#13;
var nodeIterator = document.createNodeIterator(
    document.body,
    NodeFilter.SHOW_COMMENT,    
    { acceptNode: function(node) { return NodeFilter.FILTER_ACCEPT; } }
);

// Replace all comment nodes with a div
while(nodeIterator.nextNode()){
    var commentNode = nodeIterator.referenceNode;
    var id = (commentNode.textContent.split(":")[1] || "").trim();
    var div = document.createElement("div");
    div.id = id;
    commentNode.parentNode.replaceChild(div, commentNode);
}
&#13;
#header,
#content,
#some_id{
  margin: 1em 0;
  padding: 0.2em;
  border: 2px grey solid;
}

#header::after,
#content::after,
#some_id::after{
  content: "DIV with ID=" attr(id);
}
&#13;
<html>
<head>
</head>
<body>
<div id="header"></div>
<div id="content"></div>
<!-- sidebar place holder: some_id -->
</body>
</html>
&#13;
&#13;
&#13;

修改:使用NodeIterator代替TreeWalker

答案 5 :(得分:0)

这是一个老问题,但这是关于DOM“占位符”的两分钱 IMO注释元素非常适合这项工作(有效的HTML,不可见,不会以任何方式误导)。 但是,如果以相反的方式构建代码,则无需遍历dom寻找注释。

我建议使用以下方法:

  1. 使用您选择的标记标记您想要“控制”的地方(例如,具有特定类别的div元素)

    <div class="placeholder"></div>
    <div class="placeholder"></div>
    <div class="placeholder"></div>
    <div class="placeholder"></div>
    <div class="placeholder"></div>
    
  2. 以通常的方式查找占位符(querySelector / classSelector等)

  3. var placeholders = document.querySelectorAll('placeholder');

    1. 将其替换为评论,并继续参考这些评论:
    2. var refArray = [];

      [...placeholders].forEach(function(placeholder){ var comment = document.createComment('this is a placeholder'); refArray.push( placeholder.parentNode.replaceChild(comment, placeholder) ); });

      在此阶段,您呈现的标记应如下所示:

      <!-- this is a placeholder -->
      <!-- this is a placeholder -->
      <!-- this is a placeholder -->
      <!-- this is a placeholder -->
      <!-- this is a placeholder -->
      
      1. 现在你可以直接使用你构建的refArray访问这些评论中的每一条,并且做你想做的事情......例如:
      2. 用标题替换第二条评论

        let headline = document.createElement('h1'); headline.innerText = "I am a headline!"; refArray[1].parentNode.replaceChild(headline,refArray[1]);

答案 6 :(得分:0)

如果您只想从文档或文档的一部分中获取所有注释的数组,那么这是我发现在现代JavaScript中最有效的方法。

function getComments (root) {

    var treeWalker = document.createTreeWalker(
        root,
        NodeFilter.SHOW_COMMENT,
        {
            "acceptNode": function acceptNode (node) {
                return NodeFilter.FILTER_ACCEPT;
            }
        }
    );

    // skip the first node which is the node specified in the `root`
    var currentNode = treeWalker.nextNode();

    var nodeList = [];
    while (currentNode) {

        nodeList.push(currentNode);
        currentNode = treeWalker.nextNode();

    }

    return nodeList;

}

我在Chrome 80中每秒获得超过50,000次操作,而堆栈和递归方法在Chrome 80中每秒都获得不到5,000次操作。我在Node.js中处理了成千上万的复杂文档,最适合我。

https://jsperf.com/getcomments/6

答案 7 :(得分:0)

使用 document.evaluate 和 xPath:

function getAllComments(node) {
    const xPath = "//comment()",
        result = [];

    let query = document.evaluate(xPath, node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
    for (let i = 0, length = query.snapshotLength; i < length; ++i) {
        result.push(query.snapshotItem(i));
    }

    return result;
}

getAllComments(document.documentElement);

根据我的测试,使用 xPath 比 treeWalker 更快: https://jsben.ch/Feagf