Jakie są możliwe przyczyny document.getElementById
, $("#id")
lub jakakolwiek inna metoda DOM / selektor jQuery nie znalezienie elementów?
Przykładowe problemy obejmują:
- jQuery po cichu nie powiąże procedury obsługi zdarzeń
- jQuery metody "getter" (
.val()
,.html()
,.text()
) powrocieundefined
- Zwraca standardową metodę DOM,
null
powodując jeden z kilku błędów:
Uncaught TypeError: Nie można ustawić właściwości „...” o wartości null Uncaught TypeError: Nie można odczytać właściwości „...” o wartości null
Najczęstsze formy to:
Uncaught TypeError: Nie można ustawić właściwości „onclick” wartości null
Uncaught TypeError: Nie można odczytać właściwości „addEventListener” o wartości null
Uncaught TypeError: Nie można odczytać właściwości „style” wartości null
javascript
jquery
dom
Felix Kling
źródło
źródło
Odpowiedzi:
Element, który próbujesz znaleźć, nie był w DOM podczas uruchamiania skryptu.
Pozycja skryptu zależnego od DOM może mieć głęboki wpływ na jego zachowanie. Przeglądarki analizują dokumenty HTML od góry do dołu. Elementy są dodawane do DOM, a skrypty są (generalnie) uruchamiane w miarę ich napotykania. Oznacza to, że kolejność ma znaczenie. Zazwyczaj skrypty nie mogą znaleźć elementów, które pojawią się później w znacznikach, ponieważ elementy te nie zostały jeszcze dodane do DOM.
Rozważ następujące znaczniki; skrypt nr 1 nie może znaleźć,
<div>
dopóki skrypt nr 2 się powiedzie:Co powinieneś zrobić? Masz kilka opcji:
Opcja 1: przenieś skrypt
Przenieś skrypt dalej w dół strony, tuż przed zamykającym tagiem treści. Zorganizowana w ten sposób reszta dokumentu jest analizowana przed wykonaniem skryptu:
Uwaga: Umieszczanie skryptów na dole jest ogólnie uważane za najlepszą praktykę .
Opcja 2: jQuery's
ready()
Odłóż skrypt, aż DOM zostanie całkowicie przeanalizowany, używając :
$(handler)
Uwaga: Można po prostu wiążą się
DOMContentLoaded
albo ale każdy ma swoje zastrzeżenia. jQuery's dostarcza rozwiązanie hybrydowe.window.onload
ready()
Opcja 3: Delegacja wydarzenia
Gdy element wywołuje zdarzenie (pod warunkiem, że jest to wydarzenie bąbelkowe i nic nie powstrzymuje jego propagacji), każdy rodzic w przodku tego elementu również odbiera zdarzenie. To pozwala nam dołączyć moduł obsługi do istniejącego elementu i przykładowe zdarzenia, gdy pojawiają się one z jego potomków ... nawet tych dodanych po podłączeniu modułu obsługi. Wszystko, co musimy zrobić, to sprawdzić zdarzenie, aby zobaczyć, czy zostało wywołane przez żądany element, a jeśli tak, uruchom nasz kod.
jQuery
on()
wykonuje dla nas tę logikę. Podajemy po prostu nazwę zdarzenia, selektor żądanego potomka i moduł obsługi zdarzenia:Uwaga: Zazwyczaj ten wzór jest zarezerwowany dla elementów, które nie istniały w czasie ładowania lub aby uniknąć dołączania dużej liczby procedur obsługi. Warto również zauważyć, że chociaż dołączyłem przewodnik
document
(w celach demonstracyjnych), należy wybrać najbliższego wiarygodnego przodka.Opcja 4:
defer
AtrybutUżyj
defer
atrybutu<script>
.Dla odniesienia, oto kod z tego zewnętrznego skryptu :
Uwaga:
defer
Atrybut z pewnością wygląda jak magiczna kula, ale należy pamiętać o zastrzeżeniach ...1.
defer
Można go używać tylko w przypadku zewnętrznych skryptów, tj. Tych, które mająsrc
atrybut.2. być świadomym obsługi przeglądarki , tzn .: implementacji błędów w IE <10
źródło
<head>
i używamdefer
skryptów (nie muszę obsługiwać starych, niezgodnych przeglądarek)defer
iasync
mają dość szerokie wsparcie -Nawet sięgającą niektórych znacznie starszych wersji przeglądarek. Mają dodatkową zaletę polegającą na wyraźnym, wyraźnym sygnalizowaniu zamierzonego zachowania. Pamiętaj tylko, że te atrybuty działają tylko w przypadku skryptów określającychsrc
atrybut, tj. Skryptów zewnętrznych. Zważyć korzyści. Może użyć obu? Twoja decyzja.Krótko i prosto: ponieważ elementy, których szukasz, nie istnieją w dokumencie (jeszcze).
Dla pozostałej części tej odpowiedzi użyję
getElementById
jako przykładu, ale to samo dotyczygetElementsByTagName
,querySelector
i każda inna metoda elementów DOM że wybiera.Możliwe przyczyny
Istnieją dwa powody, dla których element może nie istnieć:
Element z przekazanym identyfikatorem naprawdę nie istnieje w dokumencie. Powinieneś dokładnie sprawdzić, czy identyfikator, który przekazujesz,
getElementById
naprawdę pasuje do identyfikatora istniejącego elementu w (wygenerowanym) kodzie HTML i czy nie wpisałeś błędnej nazwy (w identyfikatorach rozróżniana jest wielkość liter !).Nawiasem mówiąc, w większości współczesnych przeglądarek , które implementują
querySelector()
iquerySelectorAll()
metody, notacja w stylu CSS jest używana do pobierania elementu przez jegoid
, na przykład:document.querySelector('#elementID')
w przeciwieństwie do metody, za pomocą której element jest pobierany przez jegoid
poddocument.getElementById('elementID')
; w pierwszej#
postać jest niezbędna, w drugiej prowadziłaby do nieodzyskiwania elementu.Element nie istnieje w momencie, w którym dzwonisz
getElementById
.Ten drugi przypadek jest dość powszechny. Przeglądarki parsują i przetwarzają HTML od góry do dołu. Oznacza to, że każde wywołanie elementu DOM, które nastąpi przed pojawieniem się tego elementu DOM w kodzie HTML, zakończy się niepowodzeniem.
Rozważ następujący przykład:
div
Pojawia się poscript
. W momencie wykonania skryptu element jeszcze nie istnieje igetElementById
powrócinull
.jQuery
To samo dotyczy wszystkich selektorów z jQuery. jQuery nie znajdzie elementów, jeśli źle wpisałeś selektor lub próbujesz je wybrać, zanim one faktycznie istnieją .
Dodatkową niespodzianką jest to, że jQuery nie został znaleziony, ponieważ skrypt został załadowany bez protokołu i działa z systemu plików:
ta składnia służy do umożliwienia załadowania skryptu przez HTTPS na stronie z protokołem https: // oraz do załadowania wersji HTTP na stronie z protokołem http: //
Ma niefortunny efekt uboczny próby załadowania i niepowodzenia
file://somecdn.somewhere.com...
Rozwiązania
Przed wykonaniem wywołania
getElementById
(lub jakiejkolwiek innej metody DOM w tym zakresie) upewnij się, że istnieją elementy, do których chcesz uzyskać dostęp, tzn. Że DOM jest załadowany.Można to zapewnić, umieszczając JavaScript za odpowiednim elementem DOM
w takim przypadku możesz również wstawić kod tuż przed zamykającym tagiem body (
</body>
) (wszystkie elementy DOM będą dostępne w momencie wykonywania skryptu).Inne rozwiązania obejmują nasłuchiwanie zdarzeń
load
[MDN] lubDOMContentLoaded
[MDN] . W takich przypadkach nie ma znaczenia, gdzie w dokumencie umieszczasz kod JavaScript, musisz tylko pamiętać o umieszczeniu całego kodu przetwarzania DOM w procedurach obsługi zdarzeń.Przykład:
Więcej informacji na temat obsługi zdarzeń i różnic w przeglądarkach można znaleźć w artykułach na quirksmode.org .
jQuery
Najpierw upewnij się, że jQuery jest poprawnie załadowany. Skorzystaj z narzędzi programistycznych przeglądarki, aby dowiedzieć się, czy plik jQuery został znaleziony, a jeśli nie, popraw adres URL (np. Dodaj schemat
http:
lubhttps:
na początku, dostosuj ścieżkę itp.)Słuchanie
load
/DOMContentLoaded
events jest dokładnie tym, co robi jQuery z.ready()
[docs] . Cały kod jQuery, który wpływa na element DOM, powinien znajdować się w module obsługi zdarzeń.W rzeczywistości samouczek jQuery wyraźnie stwierdza:
Alternatywnie możesz również użyć składni skróconej:
Oba są równoważne.
źródło
ready
wydarzenia, aby odzwierciedlić preferowaną składnię „nowszą”, czy też lepiej pozostawić ją taką, jaka jest, aby działała w starszych wersjach?$(window).load()
(i ewentualnie składniowe alternatywy dla$(document).ready()
,$(function(){})
Wydaje powiązane, ale to? Czuje lekko styczna do punktu robisz..load
. Jeśli chodzi o alternatywy składniowe, można je przejrzeć w dokumentacji, ale ponieważ odpowiedzi powinny być samodzielne, warto je dodać. Z drugiej strony jestem całkiem pewien, że ten konkretny fragment dotyczący jQuery został już odebrany i prawdopodobnie jest ujęty w innych odpowiedziach i połączenie z nim może wystarczyć..load
jest przestarzały: api.jquery.com/load-event . Nie wiem, czy dotyczy to tylko zdjęć, czywindow
też.Powody, dla których selektory oparte na identyfikatorze nie działają
Rozwiązania
Spróbuj uzyskać dostęp do elementu po jego deklaracji lub alternatywnie użyj rzeczy takich jak
$(document).ready();
W przypadku elementów pochodzących z odpowiedzi Ajax, użyj
.bind()
metody jQuery. Starsze wersje jQuery miały.live()
to samo.Użyj narzędzi [na przykład wtyczki dla programistów do przeglądarek], aby znaleźć zduplikowane identyfikatory i je usunąć.
źródło
Jak wskazał @FelixKling, najbardziej prawdopodobnym scenariuszem jest to, że węzły, których szukasz, nie istnieją (jeszcze).
Jednak współczesne praktyki programistyczne często mogą manipulować elementami dokumentu poza drzewem dokumentu albo za pomocą DocumentFragments, albo po prostu bezpośrednio odłączając / ponownie podłączając bieżące elementy. Takie techniki mogą być stosowane jako część szablonów JavaScript lub w celu uniknięcia nadmiernych operacji odświeżania / ponownego wlewania, podczas gdy elementy są mocno zmieniane.
Podobnie, nowa funkcja „Shadow DOM” wdrażana w nowoczesnych przeglądarkach pozwala elementom wchodzić w skład dokumentu, ale nie można go wyszukiwać w document.getElementById i wszystkich jego metodach rodzeństwa (querySelector itp.). Odbywa się to w celu enkapsulacji funkcjonalności i jej ukrywania.
Ponownie jednak najprawdopodobniej element, którego szukasz, po prostu nie ma (jeszcze) w dokumencie i powinieneś zrobić, jak sugeruje Felix. Należy jednak pamiętać, że coraz częściej nie jest to jedyny powód, dla którego element może być nieodnawialny (tymczasowo lub na stałe).
źródło
Jeśli element, do którego próbujesz uzyskać dostęp, znajduje się w środku
iframe
i spróbujesz uzyskać do niego dostęp poza kontekstem,iframe
spowoduje to również awarię.Jeśli chcesz uzyskać element w ramce iframe, możesz dowiedzieć się, jak to zrobić tutaj .
źródło
Jeśli kolejność wykonywania skryptu nie jest problemem, inną możliwą przyczyną problemu jest niewłaściwy wybór elementu:
getElementById
wymaga, aby przekazany ciąg znaków był dosłownie identyfikatorem i nic więcej. Jeśli poprzedzony ciąg zostanie poprzedzony a#
, a identyfikator nie zaczyna się od a#
, nic nie zostanie wybrane:Podobnie, dla
getElementsByClassName
, nie poprzedzaj przekazanego ciągu ciągiem.
:W przypadku querySelector, querySelectorAll i jQuery, aby dopasować element o określonej nazwie klasy, wstaw
.
bezpośrednio przed klasą. Podobnie, aby dopasować element o określonym identyfikatorze, umieść#
bezpośrednio przed identyfikatorem:Reguły tutaj są w większości przypadków identyczne z tymi dla selektorów CSS i można je szczegółowo zobaczyć tutaj .
Aby dopasować element, który ma dwa lub więcej atrybutów (np. Dwie nazwy klas lub nazwę klasy i
data-
atrybut), umieść selektory dla każdego atrybutu obok siebie w ciągu selektora, bez spacji oddzielającej je (ponieważ spacja wskazuje selektor potomka ). Na przykład, aby wybrać:użyj ciągu zapytania
.foo.bar
. Wybraćużyj ciągu zapytania
.foo[data-bar="someData"]
. Aby wybrać<span>
poniżej:użyć
div.parent > span[data-username="bob"]
.Wielkie litery i pisownia mają znaczenie dla wszystkich powyższych. Jeśli wielkie litery lub inna pisownia są różne, element nie zostanie wybrany:
Musisz także upewnić się, że metody mają odpowiednią wielkość liter i pisownię. Użyj jednego z:
Żadna inna pisownia lub wielkie litery nie będą działać. Na przykład
document.getElementByClassName
wyrzuci błąd.Upewnij się, że przekazujesz ciąg do tych metod wyboru. Jeśli coś przekazać, że nie jest ciągiem do
querySelector
,getElementById
itp, to prawie na pewno nie będzie działać.źródło
Kiedy wypróbowałem twój kod, zadziałało.
Jedynym powodem, dla którego Twoje wydarzenie nie działa, może być fakt, że Twój DOM nie był gotowy, a przycisk o identyfikatorze „event-btn” nie był jeszcze gotowy. Twój skrypt javascript został wykonany i próbował powiązać zdarzenie z tym elementem.
Przed użyciem elementu DOM do wiązania element ten powinien być gotowy. Można to zrobić na wiele sposobów.
Opcja 1: Możesz przenieść kod powiązania zdarzenia w ramach zdarzenia gotowości do dokumentu. Lubić:
Opcja 2: Możesz użyć zdarzenia przekroczenia limitu czasu, aby wiązanie zostało opóźnione o kilka sekund. lubić:
Opcja 3: przenieś swój skrypt javascript na dół strony.
Mam nadzieję, że to Ci pomoże.
źródło
problem polega na tym, że element „speclist” nie jest tworzony w czasie wykonywania kodu javascript. Więc wstawiłem kod javascript do funkcji i wywołałem tę funkcję w przypadku zdarzenia obciążenia ciała.
źródło
Moje rozwiązanie było nie używać id elementu zakotwiczenia:
<a id='star_wars'>Place to jump to</a>
. Najwyraźniej blazor i inne struktury spa mają problemy z przeskakiwaniem do kotwic na tej samej stronie. Aby się obejść, musiałem użyćdocument.getElementById('star_wars')
. Jednak to nie działa aż położę id w elemencie ust zamiast:<p id='star_wars'>Some paragraph<p>
.Przykład użycia bootstrap:
źródło