javascript—为什么jquery或getelementbyid之类的dom方法找不到元素?

8fq7wneg  于 2021-09-13  发布在  Java
关注(0)|答案(6)|浏览(479)

可能的原因是什么 document.getElementById , $("#id") 或者任何其他没有找到元素的dom方法/jquery选择器?
示例问题包括:
jquery静默绑定事件处理程序失败
jquery“getter”方法( .val() , .html() , .text() )返回 undefined 一种标准的dom方法 null 导致以下任何一种错误:
未捕获类型错误:无法设置null的属性“…”。未捕获类型错误:无法读取null的属性“…”
最常见的形式有:
未捕获的typeerror:无法将属性“onclick”设置为null
未捕获的typeerror:无法读取null的属性“addeventlistener”
未捕获的typeerror:无法读取null的属性“style”

yqkkidmi

yqkkidmi1#

脚本运行时,您试图查找的元素不在dom中。
依赖dom的脚本的位置会对其行为产生深远的影响。浏览器从上到下解析html文档。元素被添加到dom中,脚本(通常)在遇到它们时执行。这意味着秩序很重要。通常,脚本找不到稍后出现在标记中的元素,因为这些元素尚未添加到dom中。
考虑下面的标记;脚本#1未能找到 <div> 脚本#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>

那么,你应该怎么做?您有几个选择:

选项1:移动脚本

将脚本进一步向下移动,就在结束正文标记之前。以这种方式组织,文档的其余部分将在执行脚本之前进行解析:

<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()

使用 $(handler) :

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

注意:您可以简单地绑定到 DOMContentLoadedwindow.onload 但每一个都有它的警告。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 属性 <script> .
[ defer ,一个布尔属性,]设置为向浏览器指示脚本将在解析文档后但在触发之前执行 DOMContentLoaded .

<script src="https://gh-canon.github.io/misc-demos/log-test-click.js" defer></script>
<button id="test">click me</button>

以下是来自该外部脚本的代码供参考:

document.getElementById("test").addEventListener("click", function(e){
   console.log("clicked: %o", this); 
});

注:该 defer 属性看起来确实像一颗神奇的子弹,但重要的是要注意警告。。。

  1. defer 只能用于外部脚本,即:具有 src 属性
    2.注意浏览器支持,即ie<10中的错误实现
h5qlskok

h5qlskok2#

简短而简单:因为您要查找的元素在文档中还不存在。
对于这个答案的其余部分,我将使用 getElementById 例如,但这同样适用于 getElementsByTagName , querySelector 以及选择元素的任何其他dom方法。
可能的原因
元素可能不存在的原因有两个:
文档中确实不存在具有传递的id的元素。您应该仔细检查您传递给的id getElementById 确实匹配(生成的)html中现有元素的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>

这个 div 出现在 script . 在执行脚本时,元素还不存在,并且 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>

在这种情况下,您还可以将代码放在结束正文标记之前( </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
});

有关事件处理和浏览器差异的更多信息,请参阅quirksmode.org上的文章。
jquery
首先确保jquery已正确加载。使用浏览器的开发人员工具确定是否找到jquery文件,如果找不到则更正url(例如,添加 http:https: 开始时的方案、调整路径等)
倾听 load / DOMContentLoaded 事件正是jquery所使用的 .ready() [文件]。影响dom元素的所有jquery代码都应该在该事件处理程序中。
事实上,jquery教程明确指出:
当我们使用jquery读取或操作文档对象模型(dom)时,几乎所有的操作都是如此,我们需要确保在dom准备好后立即开始添加事件等。
为此,我们为文档注册一个就绪事件。

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

或者,您也可以使用速记语法:

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

两者是等价的。

gcuhipw9

gcuhipw93#

如果您试图访问的元素位于 iframe 您尝试在 iframe 这也会导致它失败。
如果您想在iframe中获取元素,您可以在这里了解如何获取元素。

col17t5w

col17t5w4#

基于id的选择器不起作用的原因
具有指定id的元素/dom尚不存在。
元素存在,但未在dom中注册[如果是从ajax响应动态附加的html节点]。
存在多个具有相同id的元素,导致冲突。
解决
尝试在元素声明后访问该元素,或者使用 $(document).ready(); 对于来自ajax响应的元素,请使用 .bind() jquery的方法。jquery的旧版本已经过时了 .live() 同样的。
使用工具[例如,浏览器的webdeveloper插件]查找重复ID并删除它们。

6kkfgxo0

6kkfgxo05#

正如@felixkling所指出的,最有可能的情况是,您正在寻找的节点不存在(目前)。
然而,现代开发实践通常可以使用documentfragments或直接分离/重新附着当前元素来操作文档树之外的文档元素。这些技术可以作为javascript模板的一部分使用,也可以在大量修改相关元素时避免过度的重新绘制/回流操作。
类似地,在现代浏览器中推出的新“影子dom”功能允许元素成为文档的一部分,但不能通过document.getelementbyid及其所有同级方法(queryselector等)进行查询。这样做是为了封装功能,特别是隐藏功能。
不过,您要查找的元素很可能(尚未)出现在文档中,您应该按照felix的建议进行操作。但是,您还应该意识到,这并不是元素不可修复(临时或永久)的唯一原因。

deyfvvtc

deyfvvtc6#

如果脚本执行顺序不是问题所在,则问题的另一个可能原因是未正确选择元素: getElementById 要求传递的字符串是id,而不是其他内容。如果在传递的字符串前面加上 # ,并且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的元素,

相关问题