为什么jQuery或像getElementById这样的DOM方法找不到元素?

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

示例问题包括:

jQuery默默地无法绑定事件处理程序,并且返回null的标准DOM方法导致错误:

未捕获的TypeError:无法设置null的属性“…”

当您的脚本运行时,您尝试查找的元素不在DOM中 。

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

考虑以下标记; 脚本#1无法找到

而脚本#2成功:

  
test div

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


对于本答案的其余部分,我将使用getElementById作为示例,但这同样适用于getElementsByTagNamequerySelector和任何其他选择元素的DOM方法。

可能的原因

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

  1. 文档中不存在具有传递的ID的元素。 您应该仔细检查传递给getElementById的ID是否与(生成的)HTML中现有元素的ID匹配,并且您没有拼写错误 ID(ID 区分大小写 !)。

    顺便提一下,在大多数实现querySelector()querySelectorAll()方法的当代浏览器中 ,CSS样式表示法用于通过其id检索元素,例如: document.querySelector('#elementID') ,而不是在document.getElementById('elementID')下通过其id检索元素的方法; 在第一个#字符是必不可少的,在第二个字符将导致元素不被检索。

  2. 调用getElementById 时,该元素不存在。

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

请考虑以下示例:

  

div出现 script 。 在执行脚本时,元素尚不存在, getElementById将返回null

jQuery的

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

另外一个问题是找不到jQuery,因为你已经加载了没有协议的脚本并且正在从文件系统运行:

  

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

它有尝试和无法加载file://somecdn.somewhere.com...的不幸副作用file://somecdn.somewhere.com...


解决方案

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

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

 

在这种情况下,您也可以将代码放在结束体标记( )之前(所有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文件,如果不是,则更正URL(例如,在开头添加http:https: scheme,调整路径等)

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

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

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

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

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

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

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

两者都是等价的。

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

  1. 指定了id的元素/ DOM尚不存在。
  2. 该元素存在,但它没有在DOM中注册[在从Ajax响应动态附加HTML节点的情况下]。
  3. 存在多个具有相同id的元素,这导致冲突。

解决方案

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

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

  3. 使用工具[例如,浏览器的webdeveloper插件]来查找重复的ID并将其删除。

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

但是,现代开发实践通常可以使用DocumentFragments操作文档树之外的文档元素,或者直接分离/重新附加当前元素。 这些技术可以用作JavaScript模板的一部分,或者在所讨论的元素被大量改变时避免过多的重绘/重排操作。

类似地,在现代浏览器中推出的新“Shadow DOM”function允许元素成为文档的一部分,但不能通过document.getElementById及其所有兄弟方法(querySelector等)进行查询。 这样做是为了封装function并特别隐藏它。

但是,再一次,很可能你正在寻找的元素不是(还)在文档中,你应该按照Felix的建议去做。 但是,您还应该意识到,这一点越来越不是元素可能无法实现(临时或永久)的唯一原因。

如果您尝试访问的元素位于iframe并且您尝试在iframe的上下文之外访问它,这也会导致它失败。

如果你想在iframe中获取一个元素,你可以在这里找到它。

尝试将document.getElementById放在setTimeout()

例如

 setTimeout(function(){ console.log(document.getElementById('whatever')); }, 100); 

如果这样可行,那么这只是一个时间问题。