Fel*_*ing 446 javascript jquery dom
可能的原因是什么document.getElementById
,$("#id")
或者任何其他DOM方法/ jQuery选择器没有找到元素?
示例问题包括:
.val()
,.html()
,.text()
)返回undefined
返回的标准DOM方法null
导致以下任何错误:
未捕获的TypeError:无法设置null的属性'...'未捕获的TypeError:无法读取null的属性'...'
最常见的形式是:
未捕获的TypeError:无法设置null的属性'onclick'
未捕获的TypeError:无法读取null的属性"addEventListener"
未捕获的TypeError:无法读取null的属性'style'
I a*_*ica 452
脚本运行时,您尝试查找的元素不在DOM中.
DOM依赖脚本的位置会对其行为产生深远的影响.浏览器从上到下解析HTML文档.元素被添加到DOM中,脚本(通常)在遇到它们时执行.这意味着订单很重要.通常,脚本无法找到稍后出现在标记中的元素,因为这些元素尚未添加到DOM中.
考虑以下标记; 脚本#1无法找到<div>
while脚本#2成功:
<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>
Run Code Online (Sandbox Code Playgroud)
那你该怎么办?你有几个选择:
将您的脚本向下移动到页面下方,就在关闭正文标记之前.以这种方式组织,在脚本执行之前解析文档的其余部分:
<body>
<button id="test">click me</button>
<script>
document.getElementById("test").addEventListener("click", function() {
console.log("clicked: %o", this);
});
</script>
</body><!-- closing body tag -->
Run Code Online (Sandbox Code Playgroud)
注意:在底部放置脚本通常被认为是最佳实践.
ready()
推迟脚本直到完全解析DOM,使用ready()
:
<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>
Run Code Online (Sandbox Code Playgroud)
注意:您可以简单地绑定到DOMContentLoaded
或 但每个都有其警告.jQuery 提供了一个混合解决方案.window.onload
ready()
委托事件的优点是,它们可以处理来自稍后添加到文档的后代元素的事件.
当一个元素引发一个事件时(假设它是一个冒泡事件而没有任何东西停止它的传播),该元素的祖先中的每个父元素也会接收该事件.这允许我们将一个处理程序附加到现有元素,并在事件从它的后代冒泡时对它们进行冒泡...甚至是在附加处理程序之后添加的事件.我们所要做的就是检查事件是否由所需元素引发,如果是,则运行我们的代码.
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>
Run Code Online (Sandbox Code Playgroud)
注意:通常,此模式保留用于在加载时不存在的元素或避免附加大量处理程序.值得指出的是,虽然我已经附加了一个处理程序document
(用于演示目的),但您应该选择最近的可靠祖先.
defer
属性使用的defer
属性<script>
.
[
defer
,布尔属性]设置为向浏览器指示在解析文档之后要执行脚本.
<script src="https://gh-canon.github.io/misc-demos/log-test-click.js" defer></script>
<button id="test">click me</button>
Run Code Online (Sandbox Code Playgroud)
作为参考,这是来自该外部脚本的代码:
document.getElementById("test").addEventListener("click", function(e){
console.log("clicked: %o", this);
});
Run Code Online (Sandbox Code Playgroud)
注意:该defer
属性当然看起来像一个神奇的子弹,但重要的是要注意警告......
1. defer
只能用于外部脚本,即:具有src
属性的脚本.
2.了解浏览器支持,即:IE <10中的错误实现
Fel*_*ing 143
简短:因为您正在寻找的元素(尚未)存在于文档中.
对于此答案的其余部分我将使用getElementById
作为示例,但是这同样适用于getElementsByTagName
,querySelector
以及选择元件的任何其他方法的DOM.
可能的原因
元素可能不存在的原因有两个:
文档中不存在具有传递的ID的元素.您应该仔细检查您传递的ID是否getElementById
与(生成的)HTML中现有元素的ID非常匹配,并且您没有拼写错误 ID(ID 区分大小写!).
顺便提及,在大多数当代的浏览器,其实现querySelector()
和querySelectorAll()
方法,CSS样式符号用于检索由它的元件id
,例如:document.querySelector('#elementID')
,而不是通过该元件通过其检索的方法id
下document.getElementById('elementID')
; 在第一个#
字符是必不可少的,在第二个字符中它将导致元素不被检索.
该元素不存在,此刻你打电话getElementById
.
后一种情况很常见.浏览器从上到下解析和处理HTML.这意味着在该DOM元素出现在HTML之前对DOM元素的任何调用都将失败.
请考虑以下示例:
<script>
var element = document.getElementById('my_element');
</script>
<div id="my_element"></div>
Run Code Online (Sandbox Code Playgroud)
在div
出现后的script
.在执行脚本的那一刻,元素不存在尚未和getElementById
返回null
.
jQuery的
这同样适用于使用jQuery的所有选择器.如果拼错了选择器,或者在实际存在之前尝试选择它们, jQuery将找不到元素.
一个额外的转折是找不到jQuery,因为你已经加载了没有协议的脚本并且正在从文件系统运行:
<script src="//somecdn.somewhere.com/jquery.min.js"></script>
Run Code Online (Sandbox Code Playgroud)
此语法用于允许脚本通过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>
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您也可以将代码放在结束体标记(</body>
)之前(所有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
});
Run Code Online (Sandbox Code Playgroud)
有关事件处理和浏览器差异的更多信息,请参阅quirksmode.org上的文章.
jQuery的
首先确保正确加载jQuery.使用浏览器的开发人员工具查找是否找到了jQuery文件,如果不是,则更正URL(例如,在开头添加http:
或https:
方案,调整路径等)
听取load
/ DOMContentLoaded
events正是jQuery正在使用.ready()
[docs]做的事情.影响DOM元素的所有jQuery代码都应该在该事件处理程序中.
实际上,jQuery教程明确指出:
由于我们在使用jQuery时几乎所有操作都会读取或操作文档对象模型(DOM),因此我们需要确保在DOM准备就绪后立即开始添加事件等.
为此,我们为文档注册一个ready事件.
Run Code Online (Sandbox Code Playgroud)$(document).ready(function() { // do stuff when DOM is ready });
或者,您也可以使用简写语法:
$(function() {
// do stuff when DOM is ready
});
Run Code Online (Sandbox Code Playgroud)
两者都是等价的.
sum*_*mit 14
基于id的选择器不起作用的原因
解决方案
尝试在声明后访问元素,或者使用类似的东西 $(document).ready();
对于来自Ajax响应的元素,请使用.bind()
jQuery方法.旧版本的jQuery .live()
也是如此.
使用工具[例如,浏览器的webdeveloper插件]查找重复的ID并将其删除.
Nat*_*bna 12
正如@FelixKling指出的那样,最可能的情况是您正在寻找的节点(尚未存在).
但是,现代开发实践通常可以使用DocumentFragments操作文档树之外的文档元素,或者直接分离/重新附加当前元素.这些技术可以用作JavaScript模板的一部分,或者在所讨论的元素被大量改变时避免过多的重绘/重排操作.
类似地,在现代浏览器中推出的新"Shadow DOM"功能允许元素成为文档的一部分,但不能通过document.getElementById及其所有兄弟方法(querySelector等)进行查询.这样做是为了封装功能并特别隐藏它.
但是,再一次,很可能你正在寻找的元素不是(还)在文档中,你应该按照Felix的建议去做.但是,您还应该意识到,这越来越不是元素可能无法保证(临时或永久)的唯一原因.
Cer*_*nce 11
如果脚本执行顺序不是问题,则问题的另一个可能原因是未正确选择元素:
getElementById
要求传递的字符串是 ID逐字,没有别的。如果您在传递的字符串前面加上 a #
,并且 ID 不以 a 开头#
,则不会选择任何内容:
<div id="foo"></div>
Run Code Online (Sandbox Code Playgroud)
// Error, selected element will be null:
document.getElementById('#foo')
// Fix:
document.getElementById('foo')
Run Code Online (Sandbox Code Playgroud)
同样,对于getElementsByClassName
,不要在传递的字符串前加上前缀.
:
<div class="bar"></div>
Run Code Online (Sandbox Code Playgroud)
// Error, selected element will be undefined:
document.getElementsByClassName('.bar')[0]
// Fix:
document.getElementsByClassName('bar')[0]
Run Code Online (Sandbox Code Playgroud)
使用 querySelector、querySelectorAll 和 jQuery,要匹配具有特定类名的元素,请将 a.
直接放在类之前。类似地,要匹配具有特定 ID 的元素,请#
直接在 ID 之前放置一个:
<div class="baz"></div>
Run Code Online (Sandbox Code Playgroud)
// Error, selected element will be null:
document.querySelector('baz')
$('baz')
// Fix:
document.querySelector('.baz')
$('.baz')
Run Code Online (Sandbox Code Playgroud)
要匹配具有两个或多个属性的元素(例如两个类名,或一个类名和一个data-
属性),请将每个属性的选择器在选择器字符串中彼此相邻放置,不要用空格分隔它们(因为空格表示的后代选择)。例如,要选择:
<div class="foo bar"></div>
Run Code Online (Sandbox Code Playgroud)
使用查询字符串.foo.bar
。选择
<div class="foo" data-bar="someData"></div>
Run Code Online (Sandbox Code Playgroud)
使用查询字符串.foo[data-bar="someData"]
。要选择<span>
以下内容:
<div class="parent">
<span data-username="bob"></span>
</div>
Run Code Online (Sandbox Code Playgroud)
使用div.parent > span[data-username="bob"]
.
资本和拼写事情做上述所有的。如果大小写不同,或者拼写不同,元素将不会被选中:
<div class="result"></div>
Run Code Online (Sandbox Code Playgroud)
// Error, selected element will be null:
document.querySelector('.results')
$('.Result')
// Fix:
document.querySelector('.result')
$('.result')
Run Code Online (Sandbox Code Playgroud)
您还需要确保这些方法具有正确的大小写和拼写。使用以下之一:
$(selector)
document.querySelector
document.querySelectorAll
document.getElementsByClassName
document.getElementsByTagName
document.getElementById
Run Code Online (Sandbox Code Playgroud)
任何其他拼写或大写都不起作用。例如,document.getElementByClassName
会抛出错误。
确保将字符串传递给这些选择器方法。如果传递的东西是不是一个字符串querySelector
,getElementById
等等,几乎可以肯定是行不通的。
如果要选择的元素的 HTML 属性被引号包围,则它们必须是纯直引号(单引号或双引号);如果您尝试按 ID、类或属性进行选择,则像‘
或这样的卷曲引号”
将不起作用。