页面的生命周期你知道吗

337 阅读4分钟

这是我参与8月更文挑战的第25天,活动详情查看:            8月更文挑战 ​

序言

在我们日常工作中,偶尔会有一些需求,需要在页面的生命周期上做一些操作,以至于让我们在合适的时间点,触发我们的事件,我们今天就来细看一下页面的生命周期中的一些方法,看看我们平时用的对不对,有没有可以优化的地方。 今天我们主要讲以下四个事件:

  1. DOMContentLoaded 事件 —— DOM 已经就绪,因此处理程序可以查找 DOM 节点,并初始化接口。
  2. load 事件 —— 外部资源已加载完成,样式已被应用,图片大小也已知了。
  3. beforeunload 事件 —— 用户正在离开:我们可以检查用户是否保存了更改,并询问他是否真的要离开。
  4. unload 事件 —— 用户几乎已经离开了,但是我们仍然可以启动一些操作,例如发送统计数据。

DOMContentLoaded

DOMContentLoaded 事件发生在 document 对象上。我们常常用 addEventListener 来捕获它

document.addEventListener("DOMContentLoaded", helloCoolFish);

第一个参数是监听的事件名称,第二个是执行函数。

<script>
  function helloCoolFish() {
    alert('CoolFish DOM is ready');
​
    // 图片目前尚未加载完成(除非已经被缓存),所以图片的大小为 0x0
    alert(`Image size: ${img.offsetWidth}x${img.offsetHeight}`);
  }
​
  document.addEventListener("DOMContentLoaded", helloCoolFish);
</script><img id="img" src="https://en.js.cx/clipart/train.gif?speed=1&cache=0">

我们上例监听的是DOM加载完成的事件,这个事件中,页面中的元素还没有被加载完成,所以打印出的图片是没有宽高的,所以为0。DOMContentLoaded 事件非常简单。DOM 树准备就绪 —— 这是它的触发条件。它并没有什么特别之处。

DOMContentLoaded和脚本的关系

当页面文档中有script标签的时候,就会在构建DOM之前去运行,这是一种执行顺序的调度,因为脚本可能会修改DOM,所以在脚本运行完毕之前,不能确保DOM已经加载完毕。 下例,DOMContentLoaded 肯定在下面的这些脚本执行结束之后发生

<script>
  document.addEventListener("DOMContentLoaded", () => {
    alert("DOM ready!");
  });
</script><script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.js"></script><script>
  alert("Library loaded, inline script executed");
</script>

在上面这个例子中,我们首先会看到 Library loaded…,然后才会看到 DOM ready!

浏览器内部的自动填账号

Firefox,Chrome 和 Opera 都会在 DOMContentLoaded 中自动填充表单。 ​

例如,如果页面有一个带有登录名和密码的表单,并且浏览器记住了这些值,那么在 DOMContentLoaded 上,浏览器会尝试自动填充它们(如果得到了用户允许)。 ​

因此,如果 DOMContentLoaded 被需要加载很长时间的脚本延迟触发,那么自动填充也会等待。你可能在某些网站上看到过(如果你使用浏览器自动填充)—— 登录名/密码字段不会立即自动填充,而是在页面被完全加载前会延迟填充。这实际上是 DOMContentLoaded 事件之前的延迟。

load

当整个页面,包括样式、图片和其他资源被加载完成时,会触发 window 对象上的 load 事件。可以通过 onload 属性获取此事件。 下面的这个示例正确显示了图片大小,因为 window.onload 会等待所有图片加载完毕:

<script>
  window.onload = function() { // 与此相同 window.addEventListener('load', (event) => {
    alert('image loaded');
​
    // 此时图片已经加载完成
    alert(`Image size: ${img.offsetWidth}x${img.offsetHeight}`);
  };
</script><img id="img" src="https://en.js.cx/clipart/train.gif?speed=1&cache=0">

beforeunload

如果访问者触发了离开页面的导航(navigation)或试图关闭窗口,beforeunload 处理程序将要求进行更多确认。 如果我们要取消事件,浏览器会询问用户是否确定。 你可以通过运行下面这段代码,然后重新加载页面来进行尝试

window.onbeforeunload = function() {
 var msg = "您真的确定要删除吗?\n\n请确认!"; 
 if (confirm(msg)==true){ 
  return true; 
 }else{ 
  return false; 
 } ;
}

unload

当访问者离开页面时,window 对象上的 unload 事件就会被触发。我们可以在那里做一些不涉及延迟的操作,例如关闭相关的弹出窗口。 有一个值得注意的特殊情况是发送分析数据。 假设我们收集有关页面使用情况的数据:鼠标点击,滚动,被查看的页面区域等。 自然地,当用户要离开的时候,我们希望通过 unload 事件将数据保存到我们的服务器上。 它在后台发送数据,转换到另外一个页面不会有延迟:浏览器离开页面,但仍然在执行 sendBeacon。 使用方式如下:

let analyticsData = { /* 带有收集的数据的对象 */ };
​
window.addEventListener("unload", function() {
  navigator.sendBeacon("/analytics", JSON.stringify(analyticsData));
});
  1. 请求以 POST 方式发送。
  2. 我们不仅能发送字符串,还能发送表单以及其他格式的数据。
  3. 数据大小限制在 64kb。

当 sendBeacon 请求完成时,浏览器可能已经离开了文档,所以就无法获取服务器响应(对于分析数据来说通常为空)。 还有一个 keep-alive 标志,该标志用于在 fetch 方法中为通用的网络请求执行此类“离开页面后”的请求。