Почему jQuery или метод DOM, такой как getElementById, не находит элемент?
каковы возможные причины для document.getElementById,$("#id") или любой другой метод DOM / селектор jQuery не находит элементы?
пример проблемы включают в себя:
jQuery молча не удается привязать обработчик событий, а стандартный метод DOM возвращает null приведет к ошибке:
Uncaught TypeError: не удается установить свойство '...- нуль
6 ответов:
элемент, который вы пытались найти не в 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 не будет полностью проанализирован, используя
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>Примечание: Вы можете просто привязать к
DOMContentLoadedилиwindow.onloadно у каждого есть свои предостережения. в jQueryready()предлагает гибридное решение.
Вариант 3: Делегирование Событий
делегированные события имеют то преимущество, что они могут обрабатывать события из потомков элементов, которые добавляются в документ в более позднее время.
когда элемент вызывает событие (при условии, что это клокоча событие и ничто не остановит ее распространение), каждый родитель в родословной этого элемента также получает событие. Это позволяет нам присоединить обработчик к существующему элементу и выборке событий, когда они всплывают из его потомков... даже те, которые добавлены после прикрепления обработчика. Все, что нам нужно сделать, это проверить событие, чтобы увидеть, был ли он вызван желаемым элементом и, если да, запустите наш код.
в jQuery!--79-->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>для справки, вот код от этого внешний скрипт:
document.getElementById("test").addEventListener("click", function(e){ console.log("clicked: %o", this); });Примечание: конечно кажется как волшебная пуля но важно быть в курсе предостережений...
1.deferможно использовать только для внешних скриптов, т. е. с .
2. будьте в курсе поддержка браузеров, т. е.: багги реализация в IE
коротко и просто: потому что элементы, которые вы ищете, не существует в документе (пока).
для остальной части этого ответа я буду использовать
getElementByIdкак пример, но то же самое относится кgetElementsByTagName,querySelectorи любой другой метод DOM, который выбирает элементы.Возможные Причины
есть две причины, почему элемент не может существуют:
элемент с переданным идентификатором действительно не существует в документе. Вы должны дважды проверить, что идентификатор, который вы передаете
getElementByIdдействительно соответствует идентификатору существующего элемента в (сгенерированном) HTML и что у вас нет с ошибкой идентификатор (идентификаторы регистр!).кстати, в большинство современных браузеров, которые реализуют
querySelector()иquerySelectorAll()методы, CSS-стиль нотация используется для извлечения элемента поid, например:document.querySelector('#elementID'), в отличие от метода, с помощью которого элемент извлекается егоidподdocument.getElementById('elementID'); в первом#символ имеет важное значение, во втором случае это приведет к тому, что элемент не будет извлечен.элемент не существует на данный момент вы называете
getElementById.последний случай довольно распространен. Браузеры разбирают и обработка HTML-кода сверху вниз. Это означает, что любой вызов элемента DOM, который происходит до того, как этот элемент DOM появится в HTML, завершится ошибкой.
рассмотрим следующий пример:
<script> var element = document.getElementById('my_element'); </script> <div id="my_element"></div>The
divпоявляется после thescript. На данный момент скрипт выполнен, элемент не существует и все же иgetElementByIdвернутсяnull.jQuery
то же самое относится и ко всем селекторы с jQuery. jQuery не найдет элементы, если вы с ошибкой ваш выбор или вы пытаетесь выбрать их прежде чем они существуют на самом деле.
добавленный поворот-это когда jQuery не найден, потому что вы загрузили скрипт без протокола и работаете из файловой системы:
<script src="//somecdn.somewhere.com/jquery.min.js"></script>этот синтаксис используется, чтобы позволить скрипту загружаться через HTTPS на странице с протоколом https:// и загружать версию HTTP на странице с протоколом https: / / протокол http://
он имеет неудачный побочный эффект попытки и не удается загрузить
file://somecdn.somewhere.com...
решений
прежде чем позвонить в
getElementById(или любой метод DOM, если на то пошло), убедитесь, что элементы, к которым вы хотите получить доступ, существуют, т. е. DOM загружен.это можно обеспечить, просто поставив свой JavaScript после соответствующий элемент DOM
<div id="my_element"></div> <script> var element = document.getElementById('my_element'); </script>in вы также можете поместить код прямо перед закрывающим тегом body (
</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]. Весь ваш код jQuery, который влияет на элемент DOM, должен находиться внутри этого обработчика событий.в самом деле jQuery tutorial прямо говорится:
как почти все, что мы делаем при использовании jQuery читает или манипулирует объектной модели документа (DOM), мы должны убедиться, что мы начинаем добавлять события и т. д. как только дом будет готов.
для этого мы регистрируем события ready документа.
$(document).ready(function() { // do stuff when DOM is ready });вы также можете использовать сокращенный синтаксис:
$(function() { // do stuff when DOM is ready });оба эквивалентны.
причины, по которым селекторы на основе id не работают
- элемент / DOM с указанным идентификатором еще не существует.
- элемент существует, но он не зарегистрирован в DOM [в случае HTML-узлов, динамически добавляемых из ответов Ajax].
- присутствует более одного элемента с одинаковым идентификатором, что вызывает конфликт.
решений
попробуйте получить доступ к элементу после его декларации или, альтернативно, использовать такие вещи, как
$(document).ready();для элементов, поступающих из ответов Ajax, используйте
.bind()метод jQuery. Более старые версии jQuery имели.live()то же самое.используйте инструменты [например, плагин webdeveloper для браузеров], чтобы найти дубликаты идентификаторов и удалить их.
Как указал @FelixKling, наиболее вероятным сценарием является то, что узлы, которые вы ищете, не существуют (пока).
однако современные методы разработки часто могут манипулировать элементами документа за пределами дерева документов либо с помощью DocumentFragments, либо просто отсоединяя/повторно присоединяя текущие элементы напрямую. Такие методы могут использоваться как часть шаблонов JavaScript или во избежание чрезмерных операций перерисовки / перепрошивки, когда рассматриваемые элементы сильно перегружены измененный.
аналогично, новая функциональность "Shadow DOM", развернутая в современных браузерах, позволяет элементам быть частью документа, но не может запрашивать документ.getElementById и все его родственные методы (querySelector и др.). Это делается для инкапсуляции функциональности и специально скрыть его.
опять же, скорее всего, элемент, который вы ищете, просто не находится (пока) в документе, и вы должны сделать так, как предлагает Феликс. Тем не менее, вы следует также иметь в виду, что это все чаще не единственная причина, по которой элемент может быть не найден (временно или постоянно).
Если элемент, к которому вы пытаетесь получить доступ, находится внутри
iframeи вы пытаетесь получить доступ к нему вне контекстаiframeЭто также приведет к сбою.Если вы хотите получить элемент в iframe, вы можете найти, как здесь.
положить
document.getElementByIdinsetTimeout()например.
setTimeout(function(){ console.log(document.getElementById('whatever')); }, 100);Если это работает, то это просто проблема времени.
Comments