文档的加载是按照文档树的顺序加载的,所以获取script脚本节点后面加载的元素节点 是获取不了的。
为此提出三个解决方案。
解决方案一:使用onload事件,window.onload当页面加载完成后触发。
代码说明:
<style>
.box {
width: 100px;
height: 100px;
background-color: brown;
cursor: pointer;
}
</style>
<script>
var box=document.getElementsByClassName("box")
box[0].style.background="green"
</script>
<div class="box">我是box</div>
此时script标签写在div块前面,运行代码会报错,无法获取到box元素
运行结果:
可以看到box盒子的背景并没有改变,现在我们使用onload事件:
<style>
.box {
width: 100px;
height: 100px;
background-color: brown;
cursor: pointer;
}
</style>
<script>
window.onload=function(){
var box=document.getElementsByClassName("box")
box[0].style.background="green"
}
</script>
运行结果:
解决方案二和三:利用脚本的异步加载,需要用到两个属性async和defer,因为两者使用方式相同所以放在一起讲解。
这两个属性是在外部导入js文件时使用,当外部导入js的文件的script标签在元素节点前面时,同样会存在获取不到元素节点的情况,这时就需要用到async和defer。
演示:
创建一个js文件获取box盒子来外部导入:
接下来只需要在html文档中导入了:
<style>
.box {
width: 100px;
height: 100px;
background-color: brown;
cursor: pointer;
}
</style>
<script async src="../js/yibu.js"> //这里把async换成defer同样也能成功
</script>
<div class="box">我是box</div>
运行代码:
可见同样能够实现, 注意有些时候使用async可能达不到效果,因为它执行机制是与文档同步加载。
详细说一下async和defer:
async:有 async时,加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)。
defer:有 defer时,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但是 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。
图说明:
总结:
从实用角度来说,首先把所有脚本都丢到 </body> 之前是最佳实践,因为对于旧浏览器来说这是唯一的优化选择,此法可保证非脚本的其他一切元素能够以最快的速度得到加载和解析。