getElementsByClassName返回[]而不是异步附加节点

时间:2011-09-30 19:30:06

标签: javascript ajax getelementsbyclassname

(在第一个问题非常明确之后,我再次提出我的问题)

我遇到以下问题:

<div class="testA" id="test1"></div>

上面写的元素是预定义的。我现在通过XMLHttpRequest & Co.加载一个xml树,提供以下响应:

<response>
    <div class="colorSelector" id="0-0">
        <div class="gbSelector" id="1-0">
            <table style="none" id="2-0"></table>
        </div>
    </div>
</response>

我现在使用

附加第一个div
request.responseXML.getElementsByTagName("response")[0]
                       .getElementsByTagName("div")[0]

进入预定义的div

<div class="testA" id="test1">

最终文档如下所示(使用开发工具检查):

<div class="testA" id="test1">
    <div class="colorSelector" id="0-0">
        <div class="gbSelector" id="1-0">
            <table style="none" id="2-0"></table>
        </div>
    </div>
</div>

当我现在尝试使用<div class="colorSelector" id="0-0">获取元素getElementById("0-0")时,我得到了预期的结果。

但使用getElementsByClassName("colorSelector")会返回[]

我错过了什么吗?它可能是节点属于Element而不是HTMLElement的事实的剩余部分吗?

6 个答案:

答案 0 :(得分:3)

colorSelector已被注释掉。 JavaScript只能在DOM中运行,注释掉的部分不在DOM中。

答案 1 :(得分:1)

既然你说你的getElementById("0-0")成功了,那么显然你实际上没有注释掉节点。

我猜你在做:

document.getElementById("0-0").getElementsByClassName('colorSelector');

...这将无效,因为ID选择的元素没有该类的后代。


由于您在标记中显示HTML注释,我还想知道您是否在ID为"0-0"的页面上有一些不同的元素。看一看。


如果您的节点实际已被注释掉,则需要先选择注释,并将其替换为内部包含的标记:

var container = document.getElementById('test1'),
    comment = container.firstChild;

while( comment && comment.nodeType !== 8 ) {
    comment = comment.nextSibling;
}

if( comment ) {
    container.innerHTML = comment.nodeValue;
}

...导致:

<div class="testA" id="test1">
    <div class="colorSelector" id="0-0">
        <div class="gbSelector" id="1-0">
            <table style="none" id="2-0"></table>
        </div>
    </div>
</div>

...但是又一次,由于你的getElementsById确实有效,这似乎不太可能。

答案 2 :(得分:0)

<!--<div class="colorSelector" id="0-0">
        <div class="gbSelector" id="1-0">
            <table style="none" id="2-0"></table>
        </div>
    </div>-->

上面的代码是灰色的,原因是:这是一个评论。浏览器根本不解析注释,对页面没有任何影响。

您必须解析HTML,阅读评论,并使用评论内容制作 DOM对象。

答案 3 :(得分:0)

请描述您对返回的结果所做的工作。 nodeList和节点之间存在显着差异,nodeLists LIVE

因此,如果将getElementsByClassName()(或类似)返回的nodeList分配给变量,则当您从DOM中删除nodeList中的节点时,此变量将会更改。

答案 4 :(得分:0)

  

我现在追加第一个div

你是怎么做到的?您在responseXML中拥有的是XML元素,而不是HTML元素。

  • 您不应该appendChild将它们转换为非XHTML HTML文档;

  • 实际上你根本不应该appendChild将它们放到另一个文档中,你应该使用importNode从一个文档到另一个文档中获取元素,否则你应该得到WRONG_DOCUMENT_ERR;

  • 即使您因浏览器松弛而设法将它们插入到HTML中,它们仍然是XML元素,而不是语义上的HTML元素。因此,class属性没有什么特别之处;只是拥有该名称并不会使该属性实际上代表一个类。 getElementsByClassName不会仅仅因为它们具有名称 class的属性而返回元素;它们必须是其语言定义将属性与类的概念相关联的元素(通常意味着HTML,XHTML或SVG)。

(对于id属性也应该如此;仅仅拥有一个名为id的属性并不会使其在概念上成为ID。所以getElementById不应该通过在doctype中使用<!ATTLIST声明,有一种方法可以将任意XML属性与ID-ness相关联,而这些属性并不是通过类别来实现的。虽然通常不值得打扰。另外{ {1}}是一种特殊情况,在支持XML ID的实现中。)

如果你使用native-XHTML页面,你可以通过在内容上放置合适的xml:id属性来使其成为实际的XHTML而不仅仅是任意的XML,然后使用{{1} }。但总的来说这不值得;返回HTML标记字符串(通常是JSON)或客户端脚本可以从中构建HTML元素的原始XML数据往往更简单。

答案 5 :(得分:0)

这是Firefox,Opera,Chrome和Safari的一种方法。基本上,你只需要使用div.innerHTML = div.innerHTML将其内容重新解释为HTML,这将使XML文件中的类属性被视为HTML类名。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title></title>
        <script>
            window.addEventListener("DOMContentLoaded", function() {
                var div = document.getElementsByTagName("div")[0];
                var req = new XMLHttpRequest();
                req.onreadystatechange = function() {
                    if (this.readyState === 4 && this.status === 200) {
                        var doc = this.responseXML;
                        div.appendChild(document.importNode(doc.getElementsByTagName("response")[0].getElementsByTagName("div")[0], true));
                        div.innerHTML = div.innerHTML;
                        alert(document.getElementsByClassName("colorSelector").length);
                    }
                };
                req.open("GET", "div.xml");
                req.send();
            }, false);
        </script>
    </head>
    <body>
        <div class="testA"></div>
    </body>
</html>

如果您在本地支持xhr的浏览器中进行本地测试,请删除this.status === 200。

importNode()函数似乎在IE中不起作用(例如9)。我得到一个模糊的“界面不支持”错误。

你也可以这样做:

var doc = this.responseXML;
var markup = (new XMLSerializer()).serializeToString(doc.getElementsByTagName("response")[0].getElementsByTagName("div")[0]);
div.innerHTML = markup;

只要标记是HTML友好的,就空元素的结束标记而言。