addEventListener如果放在<head>标签里而不是<body>标签里,将无法正常工作。

3

我真的不知道为什么这个不起作用。如果我把脚本放在头部,我的HTML中,在控制台中会出现以下错误:

Uncaught TypeError: Cannot read property 'addEventListener' of null

如果我将我的脚本放在页面底部,它能够正常工作。
HTML代码如下:
<head>
    <link rel="stylesheet" type="text/css" href="style.css">
    <script type="text/javascript" src="script.js"> </script>
</head>

<body>
    <ul>
        <li><a href="#" data-img="img1" id="img1"> Shahin </a></li>
        <li><a href="#" data-img="img2" id="img2"> Lina   </a></li>
        <li><a href="#" data-img="img3" id="img3"> Adrita </a></li>
    </ul>
    <img src="./img/1.jpg" class="hidden">
    <img src="./img/2.png" class="hidden">
    <img src="./img/3.jpg" class="hidden">
</body>

JavaScript:

var shahin = document.getElementById('img1');
var lina = document.getElementById('img2');
var adrita = document.getElementById("img3");

shahin.addEventListener('click',picShow);
lina.addEventListener('click',picShow);
adrita.addEventListener('click',picShow);

function picShow() {
    console.log(this);
}

请问有人能告诉我我做错了什么,以及脚本标签应该放在哪个位置?还有,我应该做出哪些更改才能从头部运行我的脚本?期待您的回答。谢谢。


1
DOM 必须加载完成后,您才能够获取元素并附加监听器。如果您的代码位于 head 中,则在脚本运行之前 DOM 尚未加载。请将您的代码包装在 onload 或 ready 包装器中,或将其移动到 HTML 下方。 - Andy
如果你的处理程序在头部,那么你需要将它放在 $(document).ready() 中,因为当你添加处理程序时,你的页面主体还没有被渲染。 - jdubjdub
@jdubjdub,那只能在使用jQuery的情况下才有效。 - Andy
无论您想要使用什么准备状态,都可以 - 只需在DOM加载后运行的内容即可。 - jdubjdub
4个回答

3

你的脚本在加载和执行之前就被优先HTML页面的其余部分,因此,document.getElementById自然会返回null。

你应该在或之后运行事件监听器订阅代码document.ready事件。

将你发布的代码包装到一个JS函数中,然后将该函数设置为在document.ready上执行的回调函数:

document.addEventListener('load', initFn);


DOMContentLoaded 是有效的。至于 onload 我不太确定。 - Andy
W3Schools网站不再准确吗?https://www.w3schools.com/jsref/event_onload.asp - Josh E
我尝试了这段代码,但控制台上没有任何显示... 也没有错误。 `document.addEventListener('onload',function abc() {var shahin = document.getElementById('img1'); var lina = document.getElementById('img2'); var adrita = document.getElementById("img3"); shahin.addEventListener('click',picShow); lina.addEventListener('click',picShow); adrita.addEventListener('click',picShow); function picShow() { console.log(this); }}); ` - Sanjida lina
我编辑了我的回答 - 尝试使用“load”而不是“onload”作为事件的名称。 - Josh E

3
<script type="text/javascript" defer src="script.js"> </script>

添加关键词defer,脚本会在所有DOM元素加载完后运行。


2
如果您将<script>放在<head>中,JavaScript 会从上到下加载。
因此,在加载时,它会返回未定义的事件监听器。
因此,请尝试在</body>标记结束之前使用脚本,这样它就可以正常工作了。
像这样:
<script type="text/javascript" src="script.js"> </script>
</body>

请问有人能告诉我应该做什么更改才能从头开始运行脚本吗?我尝试使用document.addEventListener('onload',function abc() {并将整个代码包装在其中...但仍然无法工作... - Sanjida lina
使用defer属性 - Siva Rajesh

1

针对Josh E的回答,进一步说明:

你应该在document.ready事件上或之后运行你的事件监听器订阅代码。

如果你想在元素可用时立即执行代码,你可以使用requestAnimationFrame在页面加载期间扫描DOM,而不是等待整个页面加载完成:

function doSomethingWithElement(myElement) {
    myElement.addEventListener('click', function() {
        // Do stuff here
    });
}

function searchForElement() {
    const el = document.getElementById('img1');
    if (el) {
       return doSomethingWithEl(el); 
    }
    window.searchID = window.requestAnimationFrame(searchForElement);
}

// Store the request ID so it can be cancelled later
// Otherwise it'll run forever!
window.searchID = window.requestAnimationFrame(searchForElement);
window.addEventListener('load', function() {
    window.cancelAnimationFrame(window.searchID);
});

这可能有点过度,但当您想尽快操纵或添加监听器到DOM元素时,它非常有用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接