• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • 窗口事件

    scroll 事件

    scroll事件在文档或文档元素滚动时触发,主要出现在用户拖动滚动条。

    window.addEventListener('scroll', callback);
    

    该事件会连续地大量触发,所以它的监听函数之中不应该有非常耗费计算的操作。推荐的做法是使用requestAnimationFramesetTimeout控制该事件的触发频率,然后可以结合customEvent抛出一个新事件。

    (function () {
      var throttle = function (type, name, obj) {
        var obj = obj || window;
        var running = false;
        var func = function () {
          if (running) { return; }
          running = true;
          requestAnimationFrame(function() {
            obj.dispatchEvent(new CustomEvent(name));
            running = false;
          });
        };
        obj.addEventListener(type, func);
      };
    
      // 将 scroll 事件转为 optimizedScroll 事件
      throttle('scroll', 'optimizedScroll');
    })();
    
    window.addEventListener('optimizedScroll', function() {
      console.log('Resource conscious scroll callback!');
    });
    

    上面代码中,throttle()函数用于控制事件触发频率,它有一个内部函数func(),每次scroll事件实际上触发的是这个函数。func()函数内部使用requestAnimationFrame()方法,保证只有每次页面重绘时(每秒60次),才可能会触发optimizedScroll事件,从而实际上将scroll事件转换为optimizedScroll事件,触发频率被控制在每秒最多60次。

    改用setTimeout()方法,可以放置更大的时间间隔。

    (function() {
      window.addEventListener('scroll', scrollThrottler, false);
    
      var scrollTimeout;
      function scrollThrottler() {
        if (!scrollTimeout) {
          scrollTimeout = setTimeout(function () {
            scrollTimeout = null;
            actualScrollHandler();
          }, 66);
        }
      }
    
      function actualScrollHandler() {
        // ...
      }
    }());
    

    上面代码中,每次scroll事件都会执行scrollThrottler函数。该函数里面有一个定时器setTimeout,每66毫秒触发一次(每秒15次)真正执行的任务actualScrollHandler

    下面是一个更一般的throttle函数的写法。

    function throttle(fn, wait) {
      var time = Date.now();
      return function() {
        if ((time + wait - Date.now()) < 0) {
          fn();
          time = Date.now();
        }
      }
    }
    
    window.addEventListener('scroll', throttle(callback, 1000));
    

    上面的代码将scroll事件的触发频率,限制在一秒一次。

    lodash函数库提供了现成的throttle函数,可以直接使用。

    window.addEventListener('scroll', _.throttle(callback, 1000));
    

    本书前面介绍过debounce的概念,throttle与它区别在于,throttle是“节流”,确保一段时间内只执行一次,而debounce是“防抖”,要连续操作结束后再执行。以网页滚动为例,debounce要等到用户停止滚动后才执行,throttle则是如果用户一直在滚动网页,那么在滚动过程中还是会执行。

    resize 事件

    resize事件在改变浏览器窗口大小时触发,主要发生在window对象上面。

    var resizeMethod = function () {
      if (document.body.clientWidth < 768) {
        console.log('移动设备的视口');
      }
    };
    
    window.addEventListener('resize', resizeMethod, true);
    

    该事件也会连续地大量触发,所以最好像上面的scroll事件一样,通过throttle函数控制事件触发频率。

    fullscreenchange 事件,fullscreenerror 事件

    fullscreenchange事件在进入或退出全屏状态时触发,该事件发生在document对象上面。

    document.addEventListener('fullscreenchange', function (event) {
      console.log(document.fullscreenElement);
    });
    

    fullscreenerror事件在浏览器无法切换到全屏状态时触发。