使用惰性函数优化页面滚动事件的性能

我们在做前端开发的时候,曾遇到一些非常炫酷的宣传页。例如每一个苹果产品的主页面。我们会发现,这样炫酷的页面,总是跟随我们鼠标滚轮的操作,在页面中响应不同的事件。


一、浏览器的不同

我们都知道,需要在前端页面中监听到鼠标滚轮的事件,不同浏览器内核提供的方法是不同的。所以,每当我们需要监听鼠标滚轮事件,就需要先判断使用终端是用的什么浏览器。

在前端,我们可以通过 window.navigator.userAgent 这个浏览器自带的 API 来判断浏览器类型。其中,Chrome、FireFox、Edge 这三个如今最主流的浏览器,返回的格式如下:

浏览器userAgent 返回值
ChromeMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36
FireFoxMozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0
EdgeMozilla/5.0 (Windows NT 10.0; Win64; x64; ServiceUI 13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134

 

 

 

 

 

由于鼠标滚轮事件,只有 FireFox 浏览器比较特殊,其它浏览器都是一样的。所以我们只需要判断是否是 FireFox 浏览器即可。

const browser = window.navigator.userAgent; // 获取浏览器信息
const isFirefox = browser.toLowerCase().includes('firefox'); // 判断是不是 FireFox 浏览器

二、监听滚动事件

在 Chrome 等主流浏览器中,我们可以直接通过监听 mousewheel 事件。其对应事件处理函数中的事件对象 event 包含一个 wheelDelta 属性。当鼠标滚轮向上滚动的时候,wheelDelta 的值为 120;反之,当鼠标滚轮向下滚动的时候,wheelDelta 的值为 -120

因此,我们可以直接通过判断 wheelDelta 的值,获取对应的操作逻辑:

document.addEventListener('mousewheel', function(e) { // 其它浏览器使用 mousewheel 监听
  const ev = e || event;
  ev.wheelDelta > 0 ? console.log('向上滚动') : console.log('向下滚动'); // wheelDelta 为 -120,向下滚动;wheelDelta 为 120,向上滚动
});

在 FireFox 浏览器中,我们需要通过监听 DOMMouseScroll 事件。其对应事件处理函数中的事件对象 event 并不包含 wheelDelta 属性,而是使用 detail 代替。并且,detail 属性的值也是和事件反过来的。当鼠标滚轮向上滚动的时候,detail 的值为 -3;反之,当鼠标滚轮向下滚动的时候,detail 的值为 3

因此,在 FireFox 浏览器中,我们需要通过判断 detail 的值来获取对应的操作逻辑:

document.addEventListener('DOMMouseScroll', function(e) { // FireFox 浏览器使用 DOMMouseScroll 监听
  const ev = e || event;
  ev.detail < 0 ? console.log('向上滚动') : console.log('向下滚动'); // detail 为 3,向下滚动;detail 为 -3,向上滚动
});

 


三、完整的监听滚动函数

通过以上两步,我们可以简单的将其构建成一个完整的监听鼠标滚动的通用函数:

function scroll() {
  const browser = window.navigator.userAgent; // 获取浏览器信息
  const isFirefox = browser.toLowerCase().includes('firefox'); // 判断是不是 FireFox 浏览器
  if (isFirefox) {
    document.addEventListener('DOMMouseScroll', function(e) { // FireFox 浏览器使用 DOMMouseScroll 监听
      const ev = e || event;
      ev.detail < 0 ? console.log('向上滚动') : console.log('向下滚动'); // detail 为 3,向下滚动;detail 为 -3,向上滚动
    });
  } else {
    document.addEventListener('mousewheel', function(e) { // 其它浏览器使用 mousewheel 监听
      const ev = e || event;
      ev.wheelDelta > 0 ? console.log('向上滚动') : console.log('向下滚动'); // wheelDelta 为 -120,向下滚动;wheelDelta 为 120,向上滚动
    });
  }
}

 一般来说,函数写成,大功告成。但是咱们不妨思考这样一个问题:

对于同一个浏览器来说,每次进来都要判断浏览器类型,并做出判断,这样做是必须的吗?

比如一个 Chrome 浏览器,在第一次访问的时候,程序需要判断浏览器类型,并根据判断执行以上程序中 else 的部分。那么,从第二次开始同一个 Chrome 浏览器进行访问的时候,可以直接执行 else 部分中的代码即可,何乐而不为呢?

这样,掌声有请我们今天的主角——惰性函数。


四、惰性函数 

通过打印,我们可以看到。以上函数在每一次执行的时候,均会完整执行:

 

于是,我们巧妙的借助 JavaScript 中函数声明的特点,对函数名变量进行重新赋值,就可以巧妙地减少执行函数的大小: 

function scroll() {
  const browser = window.navigator.userAgent; // 获取浏览器信息
  const isFirefox = browser.toLowerCase().includes('firefox'); // 判断是不是 FireFox 浏览器
  if (isFirefox) {
    scroll = function () {
      document.addEventListener('DOMMouseScroll', function(e) { // FireFox 浏览器使用 DOMMouseScroll 监听
      const ev = e || event;
      ev.detail < 0 ? console.log('向上滚动') : console.log('向下滚动'); // detail 为 3,向下滚动;detail 为 -3,向上滚动
    });
    }
  } else {
    scroll = function () {
      document.addEventListener('mousewheel', function(e) { // 其它浏览器使用 mousewheel 监听
      const ev = e || event;
      ev.wheelDelta > 0 ? console.log('向上滚动') : console.log('向下滚动'); // wheelDelta 为 -120,向下滚动;wheelDelta 为 120,向上滚动
    });
    }
  }
}

在这里,我们分别把 if 和 else 中的代码都放到一个匿名函数中,并且把匿名函数赋值给一个变量。需要注意的是,这个变量并不是我们自己声明的,而是直接写了父函数的函数名 scroll。 

这里牵扯到 JavaScript 代码在浏览器加载的底层原理,不再过多展开。感兴趣的小伙伴们可以关注我以后的文章,我会在不久的将来做更加详细的讲解。

通过打印,我们发现从第二次开始,执行函数 scroll 不再是整个函数,而仅仅是我们需要执行的匿名函数。 

 

这样处理之后,程序的执行部分得到了大大的简化,也可以提升程序的执行效率。

这样,在函数体中巧用覆盖赋值的方式写的匿名函数方法,我们就叫做惰性函数

 

关注我,给您更多精彩内容!

出现这个错误的原因是在导入seaborn包时,无法从typing模块中导入名为'Protocol'的对象。 解决这个问题的方法有以下几种: 1. 检查你的Python版本是否符合seaborn包的要求,如果不符合,尝试更新Python版本。 2. 检查你的环境中是否安装了typing_extensions包,如果没有安装,可以使用以下命令安装:pip install typing_extensions。 3. 如果你使用的是Python 3.8版本以下的版本,你可以尝试使用typing_extensions包来代替typing模块来解决该问题。 4. 检查你的代码是否正确导入了seaborn包,并且没有其他导入错误。 5. 如果以上方法都无法解决问题,可以尝试在你的代码中使用其他的可替代包或者更新seaborn包的版本来解决该问题。 总结: 出现ImportError: cannot import name 'Protocol' from 'typing'错误的原因可能是由于Python版本不兼容、缺少typing_extensions包或者导入错误等原因造成的。可以根据具体情况尝试上述方法来解决该问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [ImportError: cannot import name ‘Literal‘ from ‘typing‘ (D:\Anaconda\envs\tensorflow\lib\typing....](https://blog.youkuaiyun.com/yuhaix/article/details/124528628)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值