Why does jQuery or a DOM method such as getElementById not find the element?
示例问题包括:
- jquery未自动绑定事件处理程序
- jquery"getter"方法(
.val() 、.html() 、.text() )返回undefined 。 返回
null 的标准dom方法,导致以下任何错误:
Uncaught TypeError: Cannot set property '...' of null
Uncaught TypeError: Cannot read property '...' of null最常见的形式是:
Uncaught TypeError: Cannot set property 'onclick' of null
Uncaught TypeError: Cannot read property 'addEventListener' of null
Uncaught TypeError: Cannot read property 'style' of null
脚本运行时,您试图查找的元素不在DOM中。
依赖于DOM的脚本的位置可能对其行为产生深远的影响。浏览器从上到下分析HTML文档。元素被添加到DOM中,脚本(通常)在遇到它们时执行。这意味着秩序很重要。通常,脚本找不到稍后出现在标记中的元素,因为这些元素尚未添加到DOM中。
考虑以下标记;脚本1未能找到
1 2 3 4 5 | console.log("script #1: %o", document.getElementById("test")); // null test div console.log("script #2: %o", document.getElementById("test")); // <div id="test" ... |
那么,你应该怎么做?你有几个选择:
选项1:移动脚本将脚本进一步移到页面下方,就在结束正文标记之前。以这种方式组织,在执行脚本之前解析文档的其余部分:
1 2 3 4 5 6 7 8 | <body> <button id="test">click me</button> document.getElementById("test").addEventListener("click", function() { console.log("clicked: %o", this); }); </body><!-- closing body tag --> |
注意:将脚本放在底部通常被认为是最佳实践。
方案二:jquery的使用
1 2 3 4 5 6 7 8 9 | <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"> $(document).ready(function() { $("#test").click(function() { console.log("clicked: %o", this); }); }); <button id="test">click me</button> |
注意:您可以简单地绑定到
Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time.
当一个元素引发一个事件(假设它是一个冒泡事件,并且没有任何东西停止它的传播)时,该元素祖先中的每个父元素也会接收该事件。这允许我们将一个处理程序附加到一个现有的元素和示例事件,因为它们从其后代中冒泡出来…即使是在附加了处理程序之后添加的。我们所要做的就是检查事件,看它是否由所需的元素引发,如果是的话,运行我们的代码。
jquery的
1 2 3 4 5 6 7 | <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"> $(document).on("click","#test", function(e) { console.log("clicked: %o", this); }); <button id="test">click me</button> |
注意:通常,此模式是为加载时不存在的元素保留的,或者避免附加大量的处理程序。同样值得指出的是,虽然我在
使用
[
defer , a Boolean attribute,] is set to indicate to a browser that the script is meant to be executed after the document has been parsed.
1 2 | <script src="https://gh-canon.github.io/misc-demos/log-test-click.js" defer> <button id="test">click me</button> |
以下是外部脚本中的代码以供参考:
1 2 3 | document.getElementById("test").addEventListener("click", function(e){ console.log("clicked: %o", this); }); |
注意:
简明扼要:因为您要查找的元素尚不存在于文档中。
对于这个答案的其余部分,我将使用
可能的原因
元素可能不存在的原因有两个:
文档中确实不存在具有传递的ID的元素。您应该仔细检查您传递给
顺便说一下,在大多数实现
元素在您调用
后一种情况很常见。浏览器从上到下分析和处理HTML。这意味着,对DOM元素的任何调用(在该DOM元素出现在HTML中之前发生)都将失败。
请考虑以下示例:
1 | var element = document.getElementById('my_element'); |
JQuery
这同样适用于使用jquery的所有选择器。如果您拼错了选择器的拼写或试图在元素实际存在之前选择它们,jquery将找不到元素。
如果找不到jquery,则会出现一个附加的扭曲,因为您已经加载了没有协议的脚本,并且正在从文件系统运行:
1 | <script src="//somecdn.somewhere.com/jquery.min.js"> |
此语法用于允许脚本通过https在协议为https://的页面上加载,以及在协议为http://的页面上加载http版本。/
它有一个不幸的副作用,即试图和未能加载
解决
在调用
只需将javascript放在相应的dom元素之后就可以确保这一点。
1 | var element = document.getElementById('my_element'); |
在这种情况下,您还可以将代码放在结束主体标记(