问题:为什么jQuery或诸如getElementById之类的DOM方法找不到元素?

document.getElementById$("#id")或任何其他DOM方法/ jQuery选择器找不到元素的可能原因是什么?

示例问题包括:

  • jQuery默默地未能绑定事件处理程序
  • jQuery" getter"方法(.val().html().text())返回undefined
  • 返回null的标准DOM方法会导致以下几种错误:

未捕获的TypeError:无法设置为null的属性" ..."未被捕获的TypeError:无法读取为null的属性" ..."

最常见的形式是:

未捕获的TypeError:无法将属性'onclick'设置为null

未捕获的TypeError:无法读取null的属性'addEventListener'

未捕获的TypeError:无法读取null的属性"样式"

标签:javascript,jquery,dom

回答1:

您要查找的元素不在 DOM < / a>脚本运行时。

依赖DOM的脚本的位置可能对其行为产生深远的影响。浏览器从上到下解析HTML文档。将元素添加到DOM中,并在遇到脚本时(通常)执行脚本。 这意味着顺序很重要。通常,脚本找不到在标记中稍后出现的元素,因为这些元素尚未添加到DOM。

考虑以下标记;脚本1成功执行后,脚本1无法找到

<script>
  console.log("script #1: %o", document.getElementById("test")); // null
</script>
<div id="test">test div</div>
<script>
  console.log("script #2: %o", document.getElementById("test")); // <div id="test" ...
</script>

那么,您应该怎么办?您有几种选择:


选项1:移动脚本

将脚本移动到页面的更下方,紧接在结束body标签之前。以这种方式组织的文档的其余部分在执行脚本之前已被解析:

<body>
  <button id="test">click me</button>
  <script>
    document.getElementById("test").addEventListener("click", function() {
      console.log("clicked: %o", this);
    });
  </script>
</body><!-- closing body tag -->

注意:通常认为将脚本放在底部是最佳做法


选项2:jQuery的ready()

使用 ready() <,将您的脚本推迟到DOM被完全解析为止/ a>:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
  $(document).ready(function() {
    $("#test").click(function() {
      console.log("clicked: %o", this);
    });
  });
</script>
<button id="test">click me</button>

注意:您可以简单地绑定到 DOMContentLoaded window. 加载 ,但每个都有其警告。 jQuery的 ready() 提供了一种混合解决方案。


选项3:事件委托

委派的事件的优点是,它们可以处理来自后继元素添加到文档中。

当元素引发事件时(假设它是冒泡事件,并且没有任何事件能够阻止其传播),该元素祖先中的每个父对象也会收到该事件。这使我们可以将处理程序附加到现有元素,并在事件从其后代冒泡时进行采样(甚至是附加了处理程序之后添加的事件)。我们要做的就是检查该事件以查看它是否由所需的元素引发,如果是,则运行我们的代码。

jQuery的 on() 为我们执行了该逻辑。我们只需提供一个事件名称,所需后代的选择器和事件处理程序:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
  $(document).on("click", "#test", function(e) {
    console.log("clicked: %o",  this);
  });
</script>
<button id="test">click me</button>

注意:通常,此模式保留给加载时不存在的元素,以避免附加大量处理程序。值得指出的是,虽然我已经在document上附加了一个处理程序(出于演示目的),但是您应该选择最近的可靠祖先。


选项4:defer属性

使用 defer

回答2:

简短:因为您要查找的元素尚未存在于文档中。


对于此答案的其余部分,我将使用getElementById作为示例,但对 getElementsByTagName querySelector 和任何其他选择元素的DOM方法。

可能的原因

元素可能不存在的原因有两个:

  1. 文档中实际上不存在带有传递ID的元素。您应仔细检查传递给getElementById的ID是否与(生成的)HTML中现有元素的ID真正匹配,以及您没有拼写错误(该ID为区分大小写!)。

    顺便说一句,在大多数现代浏览器中,< / a>,它实现querySelector()querySelectorAll()方法,CSS样式表示法用于通过id来检索元素,例如:document.querySelector('#elementID'),与元素通过document.getElementById(')下的id检索元素的方法相反elementID');在第一个中,#字符是必不可少的,在第二个中,它将导致无法检索该元素。

  2. 您调用getElementById的元素暂时不存在

后一种情况很常见。浏览器从上到下解析并处理HTML。这意味着在DOM元素出现在HTML中之前对DOM元素的任何调用都会失败。

请考虑以下示例:

<script>
    var element = document.getElementById('my_element');
</script>

<div id="my_element"></div>

div脚本之后后出现。在执行脚本的那一刻,元素不存在,并且getElementById将返回null

jQuery

这同样适用于所有带有jQuery的选择器。如果您选择器拼写错误,或者您尝试在它们实际存在之前选择它们,则jQuery将找不到元素。

另一种情况是找不到jQuery,因为您加载了没有协议的脚本并从文件系统运行。

<script src="//somecdn.somewhere.com/jquery.min.js"></script>

此语法用于允许脚本在协议为https://的页面上通过HTTPS加载,并在协议为http://

的页面上加载HTTP版本。

它有尝试并无法加载file://somecdn.somewhere.com...

的不幸副作用。

解决方案

在调用getElementById(或与此相关的任何DOM方法)之前,请确保要访问的元素存在,即DOM已加载。

只需将JavaScript 放在相应的DOM元素之后,即可确保这一点

<div id="my_element"></div>

<script>
    var element = document.getElementById('my_element');
</script>

在这种情况下,您也可以将代码放在结束正文标记()之前(在执行脚本时所有DOM元素都可用)。

其他解决方案包括收听 load [MDN] DOMContentLoaded [MDN] 事件。在这些情况下,将JavaScript代码放在文档中的位置并不重要,您只需要记住将所有DOM处理代码放在事件处理程序中即可。

示例:

window.onload = function() {
    // process DOM elements here
};

// or

// does not work IE 8 and below
document.addEventListener('DOMContentLoaded', function() {
    // process DOM elements here
});

有关事件处理和浏览器的更多信息,请参阅quirksmode.org上的文章。差异。

jQuery

首先请确保jQuery已正确加载。 使用浏览器的开发人员工具找出是否找到了jQuery文件并更正了网址(如果不是)(例如,在开头添加http:https:方案,调整路径等)

收听load / DOMContentLoaded事件正是jQuery使用 .ready() [docs] 。您所有影响DOM元素的jQuery代码都应在该事件处理程序内。

实际上, jQuery教程明确指出:

几乎所有使用jQuery进行的操作都会读取或操作文档对象模型(DOM),因此我们需要确保在DOM准备就绪后立即开始添加事件等。

为此,我们为文档注册了一个就绪事件。

$(document).ready(function() {
   // do stuff when DOM is ready
});

或者,您也可以使用简写语法:

$(function() {
    // do stuff when DOM is ready
});

两者都是等效的。

回答3:

基于ID的选择器不起作用的原因

  1. 指定ID的元素/ DOM尚不存在。
  2. 该元素存在,但未在DOM中注册(对于从Ajax响应动态追加的HTML节点而言)。
  3. 存在多个具有相同id的元素,这会导致冲突。

解决方案

  1. 尝试在元素声明后访问元素,或者使用诸如$(document).ready();

  2. 之类的东西
  3. 对于来自Ajax响应的元素,请使用jQuery的.bind()方法。较旧版本的jQuery具有相同的.live()

  4. 使用工具(例如,用于浏览器的webdeveloper插件)查找重复的ID并将其删除。

回答4:

正如@FelixKling指出的那样,最可能的情况是您要查找的节点不存在(尚未)。

但是,现代开发实践通常可以使用DocumentFragments或直接直接分离/重新附加当前元素来操纵文档树之外的文档元素。这样的技术可以用作JavaScript模板的一部分,或避免在所涉及的元素发生重大更改时避免过多的重画/重排操作。

类似地,跨现代浏览器推出的新" Shadow DOM"功能允许元素成为文档的一部分,但不能由document.getElementById及其所有同级方法(querySelector等)查询。这样做是为了封装功能并专门隐藏它。

不过,很可能您正在寻找的元素很简单,但尚未在文档中,您应该按照Felix的建议进行操作。但是,您还应该意识到,这不再是元素可能无法找到(临时或永久)的唯一原因。

回答5:

如果您要访问的元素在iframe内部,并且您尝试在iframe的上下文之外访问它,这也会导致它失败。 / p>

如果要在iframe中获取元素,可以在此处中找到方法。

回答6:

如果不是脚本执行顺序的问题,则此问题的另一个可能原因是未正确选择元素:

  • getElementById要求传递的字符串是ID verbatim ,而没有别的。如果您为传递的字符串加上#前缀,并且ID并非以#开头,则不会选择任何内容:

    <div id="foo"></div>
    
    // Error, selected element will be null:
    document.getElementById('#foo')
    // Fix:
    document.getElementById('foo')
    
  • 类似地,对于getElementsByClassName,不要在传递的字符串前加上前缀.

    <div class="bar"></div>
    
    // Error, selected element will be undefined:
    document.getElementsByClassName('.bar')[0]
    // Fix:
    document.getElementsByClassName('bar')[0]
    
  • 使用querySelector,querySelectorAll和jQuery,要与具有特定类名的元素匹配,请在类之前直接放置一个.。同样,要匹配具有特定ID的元素,请将#直接放在ID之前:

    <div class="baz"></div>
    
    // Error, selected element will be null:
    document.querySelector('baz')
    $('baz')
    // Fix:
    document.querySelector('.baz')
    $('.baz')
    

    此处的规则在大多数情况下与CSS选择器相同,可以在此处

  • 要匹配具有两个或更多属性(例如两个类名,或一个类名和一个data-属性)的元素,请将每个属性的选择器彼此相邻在选择器字符串中,没有用空格隔开(因为空格表示后代选择器)。例如,要选择:

    <div class="foo bar"></div>
    

    ,请使用查询字符串.foo.bar。要选择

    <div class="foo" data-bar="someData"></div>
    

    ,请使用查询字符串.foo[data-bar="someData"]。要在下面选择

    <div class="parent">
      <span data-username="bob"></span>
    </div>
    

    使用div.parent>span[data-username="bob"]

  • 大写和拼写至关重要。如果大小写不同或拼写不同,则不会选择该元素:

    <div class="result"></div>
    
    // Error, selected element will be null:
    document.querySelector('.results')
    $('.Result')
    // Fix:
    document.querySelector('.result')
    $('.result')
    
  • 您还需要确保方法具有正确的大小写和拼写。使用以下之一:

    $(selector)
    document.querySelector
    document.querySelectorAll
    document.getElementsByClassName
    document.getElementsByTagName
    document.getElementById
    

    任何其他拼写或大写字母均无效。例如,document.getElementByClassName将引发错误。

  • 确保将字符串传递给这些选择器方法。如果您将不是字符串的内容传递给querySelectorgetElementById等,则几乎肯定不会起作用。

回答7:

问题是执行javascript代码时未创建dom元素" speclist"。因此,我将javascript代码放在一个函数中,并在body onload事件中调用了该函数。

function do_this_first(){
   //appending code
}

<body onload="do_this_first()">
</body>

回答8:

我的解决方案是不使用锚元素的ID: 要跳转到的位置 。显然,blazor和其他spa框架的问题跳到了同一页面上。为了解决这个问题,我必须使用document.getElementById('star_wars')。但是,直到我将id放入段落元素中后,此方法才起作用: 某些段落

使用引导程序的示例:

<button class="btn btn-link" onclick="document.getElementById('star_wars').scrollIntoView({behavior:'smooth'})">Star Wars</button>

... lots of other text

<p id="star_wars">Star Wars is an American epic...</p>
回到顶部