• BOM 的核心是 window 对象,表示浏览器的实例。
  • window 对象在浏览器中有两重身份,一个是ECMAScript 中的 Global 对象,另一个就是浏览器窗口的 JavaScript 接口。
  • 这意味着网页中定义的所有对象、变量和函数都以 window 作为其 Global 对象,都可以访问其上定义的parseInt()等全局方法。

1. 窗口加载事件

1.1 window.onload

1551319525109.png
window.onload 是窗口 (页面)加载事件,当文档内容完全加载完成会触发该事件(包括图像、脚本文件、CSS 文件等), 就调用的处理函数。

  1. 通过window.onload可以将js代码写在页面元素的上方,不受加载顺序的影响,这是因为onload是在页面加载完毕后再对其内部的代码进行执行
  2. window.load只能执行一次,当写入多个时最后一个会覆盖掉前面的
  3. 当然,如果在外面包一层addEvenListener(事件添加函数)则不会限制次数

load 事件可能是 JavaScript 中最常用的事件。在 window 对象上,load 事件会在整个页面(包括所有外部资源如图片、JavaScript 文件和 CSS 文件)加载完成后触发。可以通过两种方式指定 load 事件处理程序。第一种是 JavaScript 方式

  1. window.addEventListener("load", (event) => {
  2. console.log("Loaded!");
  3. });
  • 这是使用 addEventListener()方法来指定事件处理程序。
  • 与其他事件一样,事件处理程序会接收到一个 event 对象。
  • 这个 event 对象并没有提供关于这种类型事件的额外信息,虽然在 DOM 合规的浏览器中,event.target 会被设置为 document,但在 IE8 之前的版本中,不会设置这个对象的srcElement 属性。

    第二种指定 load 事件处理程序的方式是向元素添加 onload 属性,如下所示:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>Load Event Example</title>
  5. </head>
  6. <body onload="console.log('Loaded!')">
  7. </body>
  8. </html>
  • 一般来说,任何在 window 上发生的事件,都可以通过给元素上对应的属性赋值来指定,这是因为 HTML 中没有 window 元素。
  • 这实际上是为了保证向后兼容的一个策略,但在所有浏览器中都能得到很好的支持。
  • 实际开发中要尽量使用 JavaScript 方式。

    1.2 DOMContentLoaded

    1551319620299.png
    DOMContentLoaded只有仅在会在 DOM 树构建完成后立即触发,而不用等待图片、JavaScript文件、CSS 文件或其他资源加载完成。但只在IE9以上才支持。
    相对于 load 事件,DOMContentLoaded 可以让开发者在外部资源下载的同时就能指定事件处理程序,从而让用户能够更快地与页面交互。
    要处理 DOMContentLoaded 事件,需要给 document 或 window 添加事件处理程序(实际的事件目标是 document,但会冒泡到 window)。

    1. document.addEventListener("DOMContentLoaded", (event) => {
    2. console.log("Content loaded");
    3. });
  • DOMContentLoaded 事件的 event 对象中不包含任何额外信息(除了 target 等于 document)。

  • DOMContentLoaded 事件通常用于添加事件处理程序或执行其他 DOM操作。这个事件始终在 load事件之前触发。

2. 窗口调整事件

resize

当浏览器窗口被缩放到新高度或宽度时,会触发 resize 事件。这个事件在 window 上触发,因此可以通过 JavaScript 在 window 上或者为元素添加 onresize 属性来指定事件处理程序。

  1. window.addEventListener("resize", (event) => {
  2. console.log("Resized");
  3. });
  4. //例子
  5. <script>
  6. // 注册页面加载事件
  7. window.addEventListener('load', function() {
  8. var div = document.querySelector('div');
  9. // 注册调整窗口大小事件
  10. window.addEventListener('resize', function() {
  11. // window.innerWidth 获取窗口大小
  12. console.log('变化了');
  13. if (window.innerWidth <= 800) {
  14. div.style.display = 'none';
  15. } else {
  16. div.style.display = 'block';
  17. }
  18. })
  19. })
  20. </script>
  21. <div></div>

注意 :

  1. 浏览器窗口在最大化和最小化时也会触发 resize 事件。
  2. 我们经常利用这个事件完成响应式布局。 window.innerWidth 当前屏幕的宽度。

3. 窗口关闭事件

3.1 beforeunload 事件

  • beforeunload 事件会在 window 上触发,用意是给开发者提供阻止页面被卸载的机会。
  • 这个事件会在页面即将从浏览器中卸载时触发,如果页面需要继续使用,则可以不被卸载。
  • 这个事件不能取消,否则就意味着可以把用户永久阻拦在一个页面上。
  • 相反,这个事件会向用户显示一个确认框,其中的消息表明浏览器即将卸载页面,并请用户确认是希望关闭页面,还是继续留在页面上
    1. <button>点击</button>
    2. <script>
    3. window.addEventListener("beforeunload", (e) => {
    4. e.returnValue = "你不会关闭吧,不会吧!不会吧";
    5. return false;
    6. });
    7. </script>
    注意 :
  1. 当不进行任何操作刷新时,不会弹出确认框,在进行操作后刷新则会弹出
  2. 刷新弹出确认框重新加载后再次关闭将不会再弹出确认框

4. 定时器

  • JavaScript 在浏览器中是单线程执行的,但允许使用定时器指定在某个时间之后或每隔一段时间就执行相应的代码。
  • setTimeout()用于指定在一定时间后执行某些代码
  • setInterval()用于指定每隔一段时间执行某些代码

    setTimeout()和clearTimeout

    setTimeout()方法通常接收两个参数:要执行的代码和在执行回调函数前等待的时间(毫秒)。第一个参数可以是包含 JavaScript 代码的字符串(类似于传给 eval()的字符串)或者一个函数
    1. // 在 1 秒后显示警告框
    2. setTimeout(() => alert("Hello world!"), 1000);
    第二个参数是要等待的毫秒数,而不是要执行代码的确切时间。JavaScript 是单线程的,所以每次只能执行一段代码。为了调度不同代码的执行,JavaScript 维护了一个任务队列。其中的任务会按照添加到队列的先后顺序执行。setTimeout()的第二个参数只是告诉 JavaScript 引擎在指定的毫秒数过后把任务添加到这个队列。如果队列是空的,则会立即执行该代码。如果队列不是空的,则代码必须等待前面的任务执行完才能执行。

调用 setTimeout()时,会返回一个表示该超时排期的数值 ID。这个超时 ID 是被排期执行代码的唯一标识符,可用于取消该任务。


要取消等待中的排期任务,可以调用 clearTimeout()方法并传入超时 ID

如下面的例子所示:

  1. // 设置超时任务
  2. let timeoutId = setTimeout(() => alert("Hello world!"), 1000);
  3. // 取消超时任务
  4. clearTimeout(timeoutId);
  • 只要是在指定时间到达之前调用 clearTimeout(),就可以取消超时任务。
  • 在任务执行后再调用clearTimeout()没有效果。

注意 所有超时执行的代码(函数)都会在全局作用域中的一个匿名函数中运行,因此函数中的 this 值在非严格模式下始终指向 window,而在严格模式下是 undefined。如果给 setTimeout()提供了一个箭头函数,那么 this 会保留为定义它时所在的词汇作用域。


setInterval()和clearInterval()

setInterval()setTimeout()的使用方法类似,只不过指定的任务会每隔指定时间就执行一次,直到取消循环定时或者页面卸载。setInterval()同样可以接收两个参数:要执行的代码(字符串或函数),以及把下一次执行定时代码的任务添加到队列要等待的时间(毫秒)。

  1. setInterval(() => alert("Hello world!"), 10000);

注意

  • 这里的关键点是,第二个参数,也就是间隔时间,指的是向队列添加新任务之前等待的时间。
  • 比如,调用 setInterval()的时间为 01:00:00,间隔时间为 3000 毫秒。这意味着 01:00:03 时,浏览器会把任务添加到执行队列。
  • 浏览器不关心这个任务什么时候执行或者执行要花多长时间。
  • 因此,到了 01:00:06,它会再向队列中添加一个任务。由此可看出,执行时间短、非阻塞的回调函数比较适合 setInterval()。

要取消循环定时,可以调用 clearInterval()并传入定时 ID

另一个值得注意的是,当刷新页面时,由于设置了间隔时间,所以第一次不会显示内容,需要在函数前面预先加载一次函数来启动内部功能。


setInterval()方法也会返回一个循环定时 ID,可以用于在未来某个时间点上取消循环定时。要取消循环定时,可以调用 clearInterval()并传入定时 ID。相对于 setTimeout()而言,取消定时的能力对 setInterval()更加重要。毕竟,如果一直不管它,那么定时任务会一直执行到页面卸载。
下面是一个常见的例子:

  1. let num = 0, intervalId = null;
  2. let max = 10;
  3. let incrementNumber = function() {
  4. num++;
  5. // 如果达到最大值,则取消所有未执行的任务
  6. if (num == max) {
  7. clearInterval(intervalId);
  8. alert("Done");
  9. }
  10. }
  11. intervalId = setInterval(incrementNumber, 500);

在这个例子中,变量 num 会每半秒递增一次,直至达到最大限制值。此时循环定时会被取消。这个模式也可以使用 setTimeout()来实现,比如:

  1. let num = 0;
  2. let max = 10;
  3. let incrementNumber = function() {
  4. num++;
  5. // 如果还没有达到最大值,再设置一个超时任务
  6. if (num < max) {
  7. setTimeout(incrementNumber, 500);
  8. } else {
  9. alert("Done");
  10. }
  11. }
  12. setTimeout(incrementNumber, 500);
  • 注意在使用 setTimeout()时,不一定要记录超时 ID,因为它会在条件满足时自动停止,否则会自动设置另一个超时任务。
  • 这个模式是设置循环任务的推荐做法。
  • setIntervale()在实践中很少会在生产环境下使用,因为一个任务结束和下一个任务开始之间的时间间隔是无法保证的,有些循环定时任务可能会因此而被跳过。
  • 像前面这个例子中一样使用setTimeout()则能确保不会出现这种情况。
  • 一般来说,最好不要使用 setInterval()