【问题标题】:Javascript cannot see dynamically generated elements?Javascript 看不到动态生成的元素?
【发布时间】:2016-01-04 15:31:14
【问题描述】:

不知道为什么下一个被调用的函数看不到新生成的元素?感谢帮助!! 解决方案:添加 async: false 以禁用异步功能,以确保 test-output-2 和 test-output-3 在出生过程后执行。默认情况下,ajax 使用 async: true 这有点像多线程。

function birth(mom)
{
    $.ajax(
    {url: "/cgi-bin/count.cgi",   // return 3 for sure
     async: false,   // add this to disable asynchronous feature to make sure test-output-2 and test-output-3 executed after birth process
     success: function(xkids)     // xkids is 3
     {
         for( var i = 0; i < xkids; i++ )
         {
             mom.appendChild(document.createElement("div"));
             mom.children[i].setAttribute("id", "child-"+i);
         }

         document.getElementById("test-output-1").innerHTML = mom.children.length;   // now there are 3 children
     }
    });
     document.getElementById("test-output-2").innerHTML = mom.children.length;   // there are 0 children if async: true

} 

var marry = document.getElementById("Marry"); // currently no child
birth(marry);

function whereIsTheChildren()
{
    document.getElementById("test-output-3").innerHTML = marry.children.length;   // there are 0 children if async: true
} 
whereIsTheChildren();

【问题讨论】:

标签: javascript ajax dom element


【解决方案1】:

在加载之前尝试在 DOM 中定位一个元素是行不通的(脚本一遇到它就会运行。如果它在文件中的 html 之上,则该元素将不存在,因此不会被找到)

类似地,触发 AJAX 请求然后将其视为同步操作(在执行更多代码之前等待操作完成)将不起作用。

在第一种情况下,代码是在浏览器解析 HTML 之前遇到的,因此当您尝试获取对它的引用时,该元素在 DOM 中不存在 - 这可以通过等待来修复文件以表明它已完成加载。

第二个问题是在触发birth 函数后,立即触发whereIsTheChildren 函数。不幸的是,ajax 请求仍在等待中,所以我们还没有从它那里得到我们需要使用的结果。这可以通过将调用 whereIsTheChildren 放在 ajax 请求的成功回调中来解决。

我已经做了一个简单的例子,使用 vanilla JS 和 PHP - 只需将 php 文件的请求替换为 CGI 文件。

getKidCount.php

<?php
    echo "3";
?>

index.html

<!doctype html>
<html>
<head>
<script>
"use strict";
function byId(id,parent){return (parent == undefined ? document : parent).getElementById(id);}

function myAjaxGet(url, successCallback, errorCallback)
{
    var ajax = new XMLHttpRequest();
    ajax.onreadystatechange = function()
    {
        if (this.readyState==4 && this.status==200)
            successCallback(this);
    }
    ajax.onerror = function()
    {
        console.log("AJAX request failed to: " + url);
        errorCallback(this);
    }
    ajax.open("GET", url, true);
    ajax.send();
}

window.addEventListener('load', onDocLoaded, false);

function onDocLoaded(evt)
{
    //birth(3, byId("Marry") );
    myBirth( byId('Marry') );
}

function myBirth(parentElem)
{
    myAjaxGet('getKidCount.php', onAjaxSuccess, onAjaxFail);

    function onAjaxSuccess(ajax)
    {
        var numKids = parseInt(ajax.responseText);
        for (var i=0; i<numKids; i++)
        {
            var div = document.createElement('div');
            div.id = ("child-"+i);
            parentElem.appendChild(div);
        }
        document.getElementById("test-output-1").innerHTML = parentElem.children.length;   // now there are 3 children
        whereIsTheChildren();
    }
    function onAjaxFail(ajax)
    {
        alert("Ajax failed. :(");
    }
}

function whereIsTheChildren()
{
    document.getElementById("test-output-2").innerHTML = byId('Marry').children.length;   // there are 0 children
} 


/*
function birth(xkids, mom)
{
    for( var i = 0; i < xkids; i++ )
    {
        mom.appendChild(document.createElement("div"));
        mom.children[i].setAttribute("id", "child-"+i);
    }
    document.getElementById("test-output-1").innerHTML = mom.children.length;   // now there are 3 children
} 

function birth(mom)
{
    $.ajax(
    {url: "/cgi-bin/count.cgi",   // return 3 for sure
     success: function(xkids)     // xkids is 3
     {
         for( var i = 0; i < xkids; i++ )
         {
             mom.appendChild(document.createElement("div"));
             mom.children[i].setAttribute("id", "child-"+i);
         }

         document.getElementById("test-output-1").innerHTML = mom.children.length;   // now there are 3 children
     }
     document.getElementById("test-output-2").innerHTML = mom.children.length;   // now there are 0 children
} 
*/
</script>
</head>
<body>
    <div id='test-output-1'></div>
    <div id='test-output-2'></div>
    <div id='Marry'></div>
</body>
</html>

【讨论】:

  • 非常感谢,我只是忘了补充说,出生过程是在一个回调函数中。 test-output-1 有孩子,但是在回调之后,就没有孩子了。我完全失去了理智。请帮忙。谢谢。
  • @DavidYoung - 大括号在您更新的出生函数中不匹配。紧接在url: 之前的{ 与位于左大括号下的} 匹配。换句话说,您在该函数的末尾缺少)}。突出匹配大括号的软件对此很有用 - 我使用记事本++
  • 谢谢指出。我发现问题是回调函数是并行的,所以之后的语句不等待 count.cgi&its 回调完成......换句话说,当调用 whereIsTheChildren() 时,for 语句甚至可能不会开始执行.
  • 没问题。答对了!这就是我编辑的解决方案所说的。现在应该更有帮助了。 :)
【解决方案2】:

修改为在 DOM 中表示以及在 console.log 中

function birth(xkids, mom) {
  var mom = document.querySelector(mom);
  console.log('Mom: '+mom.id);
  for (var i = 0; i < xkids; i++) {
    mom.appendChild(document.createElement("div"));
    mom.children[i].setAttribute("id", "child-" + i);
    mom.children[i].innerHTML = mom.children[i].id;
  }
  console.log(mom.id+' has '+mom.children.length+' children');
  var test = document.createElement("output");
  document.body.appendChild(test);
  test.value = mom.id + ' ' + mom.children.length;
}

birth(3, '#Marry');
birth(5, '#Liz');
birth(2, '#Betty');
div {
  outline: 1px solid black;
  width: 100px;
  height: 30px;
}
output {
  outline: 1px solid red;
  color: red;
  margin: 10px auto;
  padding: 2px;
  float: left;
}
.mom {
  outline: 1px dashed blue;
  width: 100px;
  height: auto;
  padding: 5px;
  display: inline-block;
}
<div id="Marry" class="mom">Marry</div>
<div id="Liz" class="mom">Liz</div>
<div id="Betty" class="mom">Betty</div>

【讨论】:

  • 这个例子很酷,非常感谢以更好的方式说明这一点!
  • @DavidYoung 谢谢,即使不是例外答案,您也可以投票。
【解决方案3】:

你把它放在 window.onload 事件处理程序中了吗?您的代码正在运行,请检查此fiddle

window.onload=function(){
function birth(xkids, mom)
{
    for( var i = 0; i < xkids; i++ )
    {
        mom.appendChild(document.createElement("div"));
        mom.children[i].setAttribute("id", "child-"+i);
    }

    document.getElementById("test-output-1").innerHTML = mom.children.length;   // now there are 3 children
} 

var marry = document.getElementById("Marry"); // currently no child
birth(3, marry);

function whereIsTheChildren()
{
    document.getElementById("test-output-2").innerHTML = marry.children.length;   // there are 0 children
} 
whereIsTheChildren();
}

【讨论】:

  • 谢谢回复,我刚试过,但 whereIsTheChildren() 仍然显示 0 个孩子...
  • @DavidYoung 请分享你的小提琴,或更新我的小提琴,以便我可以看到你得到的输出。
  • 对不起,我忽略了一个非常重要的部分,test-output-1 在服务器请求后的回调函数中。似乎问题就在这里,但为什么呢?
猜你喜欢
  • 1970-01-01
  • 2023-02-15
  • 1970-01-01
  • 2018-12-25
  • 2021-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多