1

你不需要 $(document).ready 和 DOMContentLoaded 了

 3 years ago
source link: https://paugram.com/coding/you-dont-need-jquery-ready-and-dom-event.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
你不需要 $(document).ready 和 DOMContentLoaded 了

你不需要 $(document).ready 和 DOMContentLoaded 了

2021.08.09进击的码农 2 90

你曾在编写原生 JS 或 JQuery 代码的时候,是不是会经常遇到 DOM 元素获取不到的问题?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="your-script.js"></script>
</head>
<body>
    <div id="app"></div>
</body>
</html>
// your-script.js
document.getElementById("app").innerHTML = "I am Paul.";
Uncaught TypeError: Cannot set property 'innerHTML' of null
    at your-script.js:1

这是因为你的代码在页面加载完成之前就已经被执行了,默认只能获取到 script 标签声明之前的内容。所以可以将 script 标签放在最后面,是平常最简单直接的办法,防止拿不到对应的 DOM 元素。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <div id="app"></div>

    <script src="your-script.js"></script>
</body>
</html>

但在某些情况下,script 标签不一定能被放在最后面,于是需要考虑到如何在页面内容加载完成后再执行代码。写过 JQuery 的同学,一定都知道 $(document).ready() 这个 API。

// JQuery
$(document).ready(function() {
  $("#app").html("I am Paul").
})

或者是原生版本:

// Vanilla
document.addEventListener("DOMContentLoaded", () => {
  document.getElementById("app").innerHTML = "I am Paul.";
})

// ! 不推荐,因为会因阻塞资源(图片等)导致长时间不会执行,就是页面所有资源加载完成之后才会执行
window.onload = function () {
  document.getElementById("app").innerHTML = "I am Paul.";
}

这里面基本上都是一个「匿名函数」封装了一波,以此实现让浏览器加载完页面内容之后才执行 script 的内容。

defer,新的帮手

然而,有一个你也许并不知道的属性,非常完美的解决这个问题。

<script src="your-script.js" defer></script>

没错,只需要在 script 标签上加一个 defer 属性,就可以让浏览器知道这个脚本需要在页面内容加载完成(不包括 onload 提到的资源阻塞)之后才执行了。完全不再需要把脚本放在最底部,或者是设置以上两个事件,就可以使用。

your-script.js 现在只需要一行代码直接执行,就可以拿到 DOM 上的内容了。

document.getElementById("app").innerHTML = "I am Paul.";

当然,相信大家并不会这样做,毕竟这样写会把变量完全公开出来,很容易被控制台获取,编写一个脚本重写代码更是「轻而易举」。实际情况去编写一段简单的代码,依然需要匿名函数的封装。

(function () {
  document.getElementById("app").innerHTML = "I am Paul.";
})();

再举个例子,Svelte 框架生成的原生代码是这样的:

var app = function () {
  ...
}();

这个你就不用担心了,连 IE10 都能用,其他浏览器基本上都是 OK 的。

CanIUse

全部带上 deferscript 标签,将和一般引入的情况执行顺序相同。

<script src="kico.js" defer></script>
<script src="your-script.js" defer></script>

如果一个带上,一个不带上,执行顺序就是先执行不带 defer 的,再执行带 defer 的。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- (2) 再执行它 -->
    <script src="your-script.js" defer></script>    
</head>
<body>
    <div id="app"></div>
    <!-- (1) 先执行 -->
    <script src="your-script-2.js"></script>
</body>
</html>

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK