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

2020/09/25 14:01 · javascript ·  · 0评论

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

问题示例包括:

  • jQuery默默地未能绑定事件处理程序
  • jQuery的“吸气”方法(.val().html().text())返回undefined
  • 返回标准DOM方法会null导致以下几种错误:

未捕获的TypeError:无法设置为null的属性“ ...”未捕获的TypeError:无法读取为null的属性“ ...”

最常见的形式是:

未捕获的TypeError:无法将属性'onclick'设置为null

未捕获的TypeError:无法读取null的属性'addEventListener'

未捕获的TypeError:无法读取null的属性“样式”

运行脚本时,您要查找的元素不在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标记之前,将脚本进一步移至页面下方。以这种方式组织的文档的其余部分将在执行脚本之前进行解析:

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

使用以下命令将脚本推迟到DOM被完全解析为止$(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>

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


选项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属性

使用的defer属性<script>

[ defer,一个Boolean属性,]设置为向浏览器指示脚本应在文档解析后但在fire之前执行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中的错误实现

简短:由于您要查找的元素在文档中不存在(尚未)。


对于此答案的其余部分我将使用getElementById作为例子,但是同样适用于getElementsByTagNamequerySelector和任何其它DOM方法,其选择的元件。

可能的原因

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

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

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

  2. 该元素您调用时不存在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() [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响应的元素,请使用.bind()jQuery方法。较旧版本的jQuery具有.live()相同的功能。

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

如果您尝试访问的元素位于内,iframe而您尝试在上下文之外进行访问,iframe这也会导致其失败。

如果要在iframe中获取元素,可以在这里找到方法

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

但是,现代开发实践通常可以使用DocumentFragments或直接直接分离/重新附加当前元素来操纵文档树之外的文档元素。此类技术可用作JavaScript模板的一部分,或避免在所涉及的元素发生重大更改时避免过多的重画/重排操作。

同样,跨现代浏览器推出的新“ Shadow DOM”功能允许元素成为文档的一部分,但不能由document.getElementById及其所有同级方法(querySelector等)查询。这样做是为了封装功能,特别是将其隐藏。

同样,尽管如此,很可能您正在寻找的元素还没有在文档中(尚未),因此您应该按照Felix的建议进行操作。但是,您还应该意识到,这不再是元素可能无法找到(临时或永久)的唯一原因。

如果不是脚本执行顺序的问题,那么另一个可能的原因是,没有正确选择元素:

  • 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的元素,请将ID #直接放在ID之前:

    <div class="baz"></div>
    
    // Error, selected element will be null:
    document.querySelector('baz')
    $('baz')
    // Fix:
    document.querySelector('.baz')
    $('.baz')
    

    在大多数情况下,此处的规则与CSS选择器的规则相同,请在此处详细查看

  • 要匹配具有两个或多个属性的元素(例如两个类名,或一个类名和一个data-属性),请将每个属性的选择器在选择器字符串中彼此相邻,不要用空格将它们分开(因为空格表示的后代选择)。例如,选择:

    <div class="foo bar"></div>
    

    使用查询字符串.foo.bar选择

    <div class="foo" data-bar="someData"></div>
    

    使用查询字符串.foo[data-bar="someData"]要选择<span>以下内容:

    <div class="parent">
      <span data-username="bob"></span>
    </div>
    

    使用div.parent > span[data-username="bob"]

  • 资本和拼写事情做上述所有的。如果大小写不同或拼写不同,则不会选择该元素:

    <div class="result"></div>
    
    // Error, selected element will be null:
    document.querySelector('.results')
    $('.Result')
    // Fix:
    document.querySelector('.result')
    $('.result')
    
  • 您还需要确保方法具有正确的大小写和拼写。使用以下之一:

    $(selector)
    document.querySelector
    document.querySelectorAll
    document.getElementsByClassName
    document.getElementsByTagName
    document.getElementById
    

    任何其他拼写或大写字母均无效。例如,document.getElementByClassName将引发错误。

  • 确保将字符串传递给这些选择器方法。如果传递的东西是不是一个字符串querySelectorgetElementById等等,几乎可以肯定是行不通的。

当我尝试您的代码时,它起作用了。

您的事件无法正常运行的唯一原因可能是您的DOM尚未准备就绪,并且ID为“ event-btn”的按钮尚未准备就绪。并且您的JavaScript已执行,并尝试将事件与该元素绑定。

在使用DOM元素进行绑定之前,应准备好该元素。有很多选择可以做到这一点。

选项1:您可以在文档就绪事件中移动事件绑定代码。喜欢:

document.addEventListener('DOMContentLoaded', (event) => {
  //your code to bind the event
});

选项2:您可以使用超时事件,以便绑定延迟几秒钟。喜欢:

setTimeout(function(){
  //your code to bind the event
}, 500);

选项3:将您的javascript包含移动到页面底部。

我希望这可以帮助你。

问题是执行javascript代码时未创建dom元素“ speclist”。因此,我将javascript代码放入一个函数中,并在body onload事件中调用了该函数。

function do_this_first(){
   //appending code
}

<body onload="do_this_first()">
</body>

我的解决方案是不使用锚元素的ID :<a id='star_wars'>Place to jump to</a>显然,blazor和其他spa框架的问题跳到了同一页面上。为了避开我不得不使用的地方document.getElementById('star_wars')但是,直到我将id放在一个段落元素中之前,这才起作用<p id='star_wars'>Some paragraph<p>

使用引导程序的示例:

<button class="btn btn-link" onclick="document.getElementById('star_wars').scrollIntoView({behavior:'smooth'})">Star Wars</button>

... lots of other text

<p id="star_wars">Star Wars is an American epic...</p>
本文地址:http://javascript.askforanswer.com/weishenmejqueryhuozhurugetelementbyidzhileidedomfangfazhaobudaoyuansu.html
文章标签: ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!