JavaScript | 事件对象—滚动事件与加载事件

457 阅读4分钟

原文:JavaScript | 事件对象—滚动事件与加载事件

滚动事件与加载事件是前端中常见的事件类型,今天对这两个知识点进行下整理

滚动事件(scroll)

滚动事件顾名思义就是滚动页面或者说是某个元素滚动的时候就会触发的事件,可以使用以下几种方式触发滚动事件:

  • 鼠标滚轮滚动
  • 使用页面右侧的滚动条
  • 使用描点跳转
  • 调用JavaScript函数

如何添加滚动事件

  • DOM Level 2 中的写法(推荐使用):

    eventTarget.addEventListener('scroll', function(){
      console.log('触发了滚动事件');
    }); 
    
  • DHTML(DOM Level 0)的写法:

    EventTarget.onscroll = function () {
      console.log('触发了滚动事件');
    }
    

如何监听整个页面的滚动

如果想要监听整个网页的滚动,给window对象添加scroll事件即可

window.addEventListener('scroll', function(){
  console.log('触发了滚动事件');
});

DHTML(DOM Level 0)的写法:

window.onscroll = function () {
  console.log('触发了滚动事件');
}

事件节流

之前一篇博客有提到,如果在事件处理的回调函数调用了下面这些属性的话,就会引起回流与重绘(因为这些属性是实时读取的),而大量的回流与重绘就会造成浏览器的卡顿。

offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight

所以可以使用节流的方式来缓解这个问题,先来了解下节流是什么:

节流:高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率

实现方式:每次触发事件时,如果当前有等待执行的延时函数,则直接return终止此次事件的执行

代码:

JS:

// 初始化 滚动标记 默认为false
let scrolling = false;

// 如果当前有滚动,则将滚动标记设置为true
window.addEventListener('scroll', function () {
  scrolling = true;
});

// 如果滚动事件触发,则每个300毫秒调用依次事件处理回调函数
setInterval(() => {
  console.log(scrolling);
  // 每次触发事件时,如果当前有等待执行的延时函数,则直接return
  if (!scrolling) {
    return;
  } else{
    // 立即设置为false
    scrolling = false
    // 处理逻辑
    window.scrollHandLer();
  }
}, 300);

function scrollHandLer() {
  // 滚动处理回调函数
  console.log('保护大籽然,不杀生');
}

加载事件(load)

加载事件,当外部资源(如图片、CSS、JavaScript文件等)加载完毕的时候触发的事件。

事件名:load

页面所有资源加载完毕后触发:

window.addEventListener('load', function(){
  console.log('外部资源加载完毕');
});

DHTML(DOM Level 0)的写法:

window.onload = function (){
  console.log('外部资源加载完毕');
}

使用场景:

在一些比较老的代码中会看到把script写在header中的写法,但是这样写会遇到一个问题

比如现在进入一个页面,会出现dom元素获取不到的问题,比如下面这种情况:

HTML:

<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>
  <script>
    let div = document.querySelector('div');
    console.log(div); //null
  </script>
</head>
<body>
  <div></div>
</body>

控制台输出:null

所以就可以通过load事件来解决这个问题,代码如下

window.addEventListener('load', function(){
  let div = document.querySelector('div');
  console.log(div);
});

控制台输出:<div></div>

当然,load事件不仅仅可以监听整个页面的资源加载,还可以针对某个资源绑定load事件

比如可以监听图片加载好之后给div元素放入文字

let img = document.querySelector('img');
img.addEventListener('load', function () {
  let div = document.querySelector('div');
  div.innerHTML = 'test';
})

补充:DOMContentLoaded

当纯 HTML 被完全加载以及解析时,DOMContentLoaded事件会被触发,而不必等待样式表,图片或者子框架完成加载

——MDN-Document: DOMContentLoaded 事件

简单理解以下就是,页面的dom树加载完成后就会触发,也就是说这个事件的触发顺序实在load事件前面的。

事件名:DOMContentLoaded

监听页面的DOM加载完成——给document添加DOMContentLoaded事件即可

document.addEventListener('DOMContentLoaded', (event) => {
  console.log('DOM fully loaded and parsed');
});

案例:

HTML:

<div class="controls">
  <button id="reload" type="button">Reload</button>
</div>

<div class="event-log">
  <label>Event log:</label>
  <textarea readonly class="event-log-contents" rows="8" cols="30"></textarea>
</div>

JS:

const log = document.querySelector('.event-log-contents');
const reload = document.querySelector('#reload');

reload.addEventListener('click', () => {
  log.textContent ='';
  window.setTimeout(() => {
      window.location.reload(true);
  }, 200);
});

window.addEventListener('load', (event) => {
    log.textContent = log.textContent + 'load\n';
});

document.addEventListener('readystatechange', (event) => {
    log.textContent = log.textContent + `readystate: ${document.readyState}\n`;
});

document.addEventListener('DOMContentLoaded', (event) => {
    log.textContent = log.textContent + `DOMContentLoaded\n`;
});

image.png

一些注意事项

  • DOMContentLoaded 事件在 html 文档加载完毕,并且 html 所引用的内联 js、以及外链 js 的同步代码都执行完毕后触发

  • 页面中引用的js 代码如果有异步加载的 js、css、图片,是会影响 load 事件触发的。

  • video、audio、flash 不会影响 load 事件触发。

参考文献