我们在做前端开发的时候,曾遇到一些非常炫酷的宣传页。例如每一个苹果产品的主页面。我们会发现,这样炫酷的页面,总是跟随我们鼠标滚轮的操作,在页面中响应不同的事件。
一、浏览器的不同
我们都知道,需要在前端页面中监听到鼠标滚轮的事件,不同浏览器内核提供的方法是不同的。所以,每当我们需要监听鼠标滚轮事件,就需要先判断使用终端是用的什么浏览器。
在前端,我们可以通过 window.navigator.userAgent 这个浏览器自带的 API 来判断浏览器类型。其中,Chrome、FireFox、Edge 这三个如今最主流的浏览器,返回的格式如下:
浏览器 | userAgent 返回值 |
---|---|
Chrome | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36 |
FireFox | Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0 |
Edge | Mozilla/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 不再是整个函数,而仅仅是我们需要执行的匿名函数。
这样处理之后,程序的执行部分得到了大大的简化,也可以提升程序的执行效率。
这样,在函数体中巧用覆盖赋值的方式写的匿名函数方法,我们就叫做惰性函数。
关注我,给您更多精彩内容!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。