Không thể đọc thuộc tính 'addEventListener' của null


106

Tôi phải sử dụng JavaScript vani cho một dự án. Tôi có một vài chức năng, một trong số đó là nút mở menu. Nó hoạt động trên các trang có id đích tồn tại, nhưng gây ra lỗi trên các trang không tồn tại id. Trên những trang mà hàm không thể tìm thấy id, tôi nhận được lỗi "Không thể đọc thuộc tính 'addEventListener' của null" và không có hàm nào khác của tôi hoạt động.

Dưới đây là mã cho nút mở menu.

function swapper() {
toggleClass(document.getElementById('overlay'), 'open');
}

var el = document.getElementById('overlayBtn');
el.addEventListener('click', swapper, false);

var text = document.getElementById('overlayBtn');
text.onclick = function(){
this.innerHTML = (this.innerHTML === "Menu") ? "Close" : "Menu";
return false;
};

Làm thế nào để đối phó với điều này? Tôi có lẽ cần phải bọc tất cả mã này trong một hàm khác hoặc sử dụng câu lệnh if / else để nó chỉ tìm kiếm id trên các trang cụ thể, nhưng không chắc chắn chính xác.


1
bạn có thể hiển thị mã html. Có vẻ như không thể tìm thấy phần tử có id 'overlayBtn'
BlaShadow

2
Trên những trang mà hàm không thể tìm thấy id, tôi nhận được lỗi "Không thể đọc thuộc tính 'addEventListener' của null" và không có hàm nào khác của tôi hoạt động. Tôi nghĩ rằng câu trả lời là khá nhiều trong câu hỏi. Bạn không thể tìm thấy nguyên tố này, vì vậy bạn không thể nghe thêm một sự kiện để nó ...
Etai

1
Nó có thể đơn giản xảy ra nếu bạn đã sử dụng classtrong html của mình thay vì idvà bạn yêu cầu một getElementByIdtrong các tập lệnh của mình.
Deke

Câu trả lời:


196

Tôi nghĩ rằng cách tiếp cận đơn giản nhất là chỉ cần kiểm tra xem nó elkhông phải là null trước khi thêm trình xử lý sự kiện:

var el = document.getElementById('overlayBtn');
if(el){
  el.addEventListener('click', swapper, false);
}

tuyệt vời. đó đã thực hiện thủ thuật. Tôi cũng đã chuyển hàm onclick vào câu lệnh if đó. Tôi đã đăng mã cuối cùng dưới đây.
morocklo,

3
nó sẽ có nulltrước khi thành phần phản ứng gắn kết!

Cảm ơn anh bạn: D Chính xác những gì tôi đang tìm kiếm .... Tôi có nhiều người nghe trong ứng dụng của mình và những người nghe được trải rộng ở các góc nhìn khác nhau. Nếu phần tử có mặt trên trang web, nó được mucking lên JS của tôi
VegaStudios

Rất hữu ích, cảm ơn!
sc_props

113

Có vẻ như nó document.getElementById('overlayBtn');đang quay trở lại nullvì nó thực thi trước khi DOM tải đầy đủ.

Nếu bạn đặt dòng mã này dưới

window.onload=function(){
  -- put your code here
}

sau đó nó sẽ chạy mà không có vấn đề.

Thí dụ:

window.onload=function(){
    var mb = document.getElementById("b");
    mb.addEventListener("click", handler);
    mb.addEventListener("click", handler2);
}


function handler() {
    $("p").html("<br>" + $("p").text() + "<br>You clicked me-1!<br>");
}

function handler2() {
    $("p").html("<br>" + $("p").text() + "<br>You clicked me-2!<br>");
}

23

Tôi đã đối mặt với một tình huống tương tự. Điều này có thể là do tập lệnh được thực thi trước khi tải trang. Bằng cách đặt tập lệnh ở cuối trang, tôi đã giải quyết được vấn đề.


1
Vâng, tôi nghĩ rằng có nhiều giải pháp cho vấn đề này tùy thuộc vào tình huống.
rpeg

16

Tôi cũng gặp phải lỗi tương tự, nhưng thực hiện kiểm tra rỗng dường như không giúp được gì.

Giải pháp mà tôi tìm thấy là bọc hàm của mình bên trong một trình xử lý sự kiện cho toàn bộ tài liệu để kiểm tra khi DOM tải xong.

document.addEventListener('DOMContentLoaded', function () {
    el.addEventListener('click', swapper, false);
});

Tôi nghĩ điều này là do tôi đang sử dụng một khuôn khổ (Angular) đang thay đổi động các lớp HTML và ID của tôi.


1
Tôi gặp phải vấn đề tương tự khi chơi với Electron. Đã lưu nó bằng cùng một phương pháp.
charles

9

Nó chỉ bcz JS của bạn được tải trước phần HTML và vì vậy nó không thể tìm thấy phần tử đó. Chỉ cần đặt toàn bộ mã JS của bạn bên trong một hàm sẽ được gọi khi cửa sổ được tải.

Bạn cũng có thể đặt mã Javascript của mình bên dưới html.


8

script đang tải trước nội dung, giữ script sau nội dung


5

Đặt tập lệnh ở cuối thẻ nội dung.

<html>
    <body>
        .........
        <script src="main.js"></script>
    </body>
</html>

3

Cảm ơn @Rob M. đã giúp đỡ. Đây là khối mã cuối cùng trông như thế nào:

function swapper() {
  toggleClass(document.getElementById('overlay'), 'open');
}

var el = document.getElementById('overlayBtn');
if (el){
  el.addEventListener('click', swapper, false);

  var text = document.getElementById('overlayBtn');
  text.onclick = function(){
    this.innerHTML = (this.innerHTML === "Menu") ? "Close" : "Menu";
    return false;
  };
}

2

Tôi chỉ cần thêm 'async' vào thẻ script của mình, điều này dường như đã khắc phục được sự cố. Tôi không chắc tại sao, nếu ai đó có thể giải thích, nhưng nó đã hiệu quả với tôi. Tôi đoán là trang này không đợi tập lệnh tải, vì vậy trang tải cùng lúc với JavaScript.

Async / Await cho phép chúng ta viết mã không đồng bộ theo kiểu đồng bộ. nó chỉ là đường cú pháp sử dụng trình tạo và câu lệnh lợi nhuận để "tạm dừng" thực thi, cho chúng tôi khả năng gán nó cho một biến!

Đây là liên kết tham khảo- https://medium.com/siliconwat/how-javascript-async-await-works-3cab4b7d21da


2

Tôi gặp phải vấn đề tương tự và đã kiểm tra null nhưng nó không giúp được gì. Bởi vì tập lệnh đã được tải trước khi tải trang. Vì vậy, chỉ cần đặt tập lệnh trước thẻ nội dung kết thúc đã giải quyết được vấn đề.


0

Như những người khác đã nói vấn đề là tập lệnh được thực thi trước khi trang (và cụ thể là phần tử đích) được tải.

Nhưng tôi không thích giải pháp sắp xếp lại nội dung.

Giải pháp ưa thích là đặt một trình xử lý sự kiện trên sự kiện tải trang và đặt Trình xử lý ở đó. Điều đó sẽ đảm bảo trang và phần tử đích được tải trước khi việc gán được thực thi. ví dụ

    <script>
    function onLoadFunct(){
            // set Listener here, also using suggested test for null
    }
    ....
    </script>

    <body onload="onLoadFunct()" ....>
    .....

0

Tôi có một bộ sưu tập các câu trích dẫn cùng với tên. Tôi đang sử dụng nút cập nhật để cập nhật báo giá cuối cùng được liên kết với một tên cụ thể nhưng khi nhấp vào nút cập nhật, nó không cập nhật. Tôi đang bao gồm mã bên dưới cho tệp server.js và tệp js bên ngoài (main.js).

main.js (js bên ngoài)

var update = document.getElementById('update');
if (update){
update.addEventListener('click', function () {

  fetch('quotes', {
  method: 'put',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({
    'name': 'Muskan',
    'quote': 'I find your lack of faith disturbing.'
  })
})var update = document.getElementById('update');
if (update){
update.addEventListener('click', function () {

  fetch('quotes', {
  method: 'put',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({
    'name': 'Muskan',
    'quote': 'I find your lack of faith disturbing.'
  })
})
.then(res =>{
    if(res.ok) return res.json()
})
.then(data =>{
    console.log(data);
    window.location.reload(true);
})
})
}

tệp server.js

app.put('/quotes', (req, res) => {
  db.collection('quotations').findOneAndUpdate({name: 'Vikas'},{
    $set:{
        name: req.body.name,
        quote: req.body.quote
    }
  },{
    sort: {_id: -1},
    upsert: true
  },(err, result) =>{
    if (err) return res.send(err);
    res.send(result);
  })

})

0

Cảm ơn tất cả, Tải tập lệnh trong các trang cụ thể mà bạn sử dụng, không phải cho tất cả các trang, đôi khi sử dụng swiper.js hoặc thư viện khác, nó có thể gây ra thông báo lỗi này, cách duy nhất để giải quyết vấn đề này là tải thư viện JS trên các trang cụ thể ID đó tồn tại và ngăn việc tải cùng một thư viện trong tất cả các trang.

Hy vọng điều này sẽ giúp bạn.


0

Tôi đã gặp vấn đề tương tự, nhưng id của tôi đã có. Vì vậy, tôi đã thử thêm "window.onload = init;" Sau đó, tôi bọc mã JS ban đầu của mình bằng một hàm init (gọi nó là những gì bạn muốn). Điều này đã hoạt động, vì vậy ít nhất trong trường hợp của tôi, tôi đã thêm một trình xử lý sự kiện trước khi tài liệu của tôi được tải. Đây cũng có thể là những gì bạn đang trải qua.


-1

Điều này là do phần tử chưa được tải tại thời điểm gói js đang được thực thi.

Tôi sẽ chuyển <script src="sample.js" type="text/javascript"></script>đến cuối index.htmltệp. Bằng cách này, bạn có thể đảm bảo tập lệnh được thực thi sau khi tất cả các phần tử html đã được phân tích cú pháp và hiển thị.


Sai. Đây là suy nghĩ cũ của trường học. Việc tải ở cuối sẽ làm chậm quá trình tải, như bạn đã nêu, nhưng nó không đảm bảo DOM được vẽ đầy đủ . Tôi đã có các trang cũ hơn sử dụng bản hack này không chạy được vì bản vẽ DOM chậm hơn tải. Câu trả lời này đảm bảo DOM được vẽ trước khi thực thi.
Machavity

-3

Thêm tất cả các trình nghe sự kiện khi một cửa sổ tải. Hoạt động như một sự quyến rũ bất kể bạn đặt thẻ tập lệnh ở đâu.

window.addEventListener("load", startup);

function startup() {

  document.getElementById("el").addEventListener("click", myFunc);
  document.getElementById("el2").addEventListener("input", myFunc);

}

myFunc(){}

Việc vẽ trang đôi khi có thể mất nhiều thời gian hơn so với việc tải tập lệnh, vì vậy vị trí không quá quan trọng trong mọi trường hợp. Thêm người nghe là cách ưa thích, nhưng loadcũng không được dùng nữa vì lý do tương tự. DOMContentLoaded là cách ưa thích, vì nó chỉ kích hoạt sau khi DOM được vẽ đầy đủ.
Machavity

Cảm ơn tôi sẽ cố gắng. Tôi đã nhận được câu trả lời từ mạng Mozilla. Tôi nghĩ đó là một nguồn đáng tin cậy.
Natalie Jimenez
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.