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

标签 javascript jquery 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的属性“样式”

最佳答案

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

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

考虑以下标记;脚本#2成功执行后,脚本#1找不到<div>



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





注意:将脚本放在底部通常被认为是best practice



选项2:jQuery的ready()

使用ready()将脚本推迟到DOM被完全解析为止:



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





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



选项3:事件委派


  Delegated events的优点在于,它们可以处理以后在文档中添加的后代元素中的事件。


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

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<script>属性。


  设置[defer,布尔值属性],向浏览器指示脚本应在文档解析后执行。




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





作为参考,下面是该external script中的代码:

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


注意:defer属性的确看起来像是魔术子弹,但是注意这些警告很重要...
1. defer仅可用于外部脚本,即:具有src属性的脚本。
2.注意browser support,即:IE <10中的错误实现

关于javascript - 为什么jQuery或诸如getElementById之类的DOM方法找不到元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56496855/

相关文章:

javascript - 动态编辑值

javascript - Kendo Datepicker 中的关闭事件多次触发

jquery - 如何使 ajaxfileupload 使用动态生成的文件输入

javascript - HTML/JavaScript : prevent paint before code executes

javascript - 语法错误: Unexpected token < : using angular 2 and webpack on heroku

php - 使用 jQuery/ajax 进行 GET 请求

javascript - 根据选择框的值隐藏div

javascript - focus() jQuery 函数在 Safari 中不起作用,但在所有其他浏览器上都能正常工作?

javascript - 在 document.ready 之后删除脚本包含标记是否总是安全的?

javascript - 创建 div 元素时奇怪的 Javascript/JQuery 行为