一、滚动条滚动事件简介

在 JavaScript 中,滚动条滚动事件是一类在滚动条滚动时触发的事件哦。简单来说,当我们操作页面的滚动条,让页面内容上下滚动或者在有滚动条的元素内部进行滚动操作时,相应的滚动事件就会被触发啦。它的应用场景可是挺广泛的呢,比如我们常见的在网页中实现 “返回顶部” 的功能时,就需要监听网页滚动条滚动事件,这个事件通常就是 window.onscroll。当这个 onscroll 事件发生了,我们可以通过 JavaScript 获取页面的 scrollTop 值,也就是滚动条向下滚动的位置,然后判断这个 scrollTop 达到我们设定的某个值时,就可以让 “返回顶部” 的按钮显示出来啦,方便用户快速回到页面顶部。再比如在做一些商品推荐展示页面的时候,为了让页面可以有较长的展示空间,就可以创建一个能够一直下拉的滚动条,也就是利用滚动条滚动事件来实现啦。具体实现时,先是在 CSS 里创建一个合适的高度,像可以设置 body{padding-bottom: 2000px;} 这样先搭建出一个大的框架,接着通过 JavaScript 代码去捕获页面的总高度(可以用 document.documentElement.scrollHeight 获取)、被卷去的高度(也就是从顶部到当前滚动位置的距离,用 document.documentElement.scrollTop 获取)以及页面的可视高度(通过 document.documentElement.clientHeight 获取),然后用总高度减去被卷去的高度再减去可视高度,就能得到页面距离底部的距离啦。之后用 if 语句进行判断,当这个距离达到某个设定值的时候,进行相应的操作,比如增加页面的高度等,再不断进行这样的判断,就能完成一个简易的滚动条事件啦。像要监听整个页面滚动的话,可以使用 window.addEventListener('scroll',function(){// 执行的具体操作}) 这样的语句哦,给 window 或者 document 添加 scroll 事件都是可行的呢。要是想监听某个元素内部的滚动情况呀,直接给对应的那个元素添加相应的滚动事件就好啦。总之,JavaScript 滚动条滚动事件在优化网页交互体验等方面起着挺重要的作用呢。
二、常见应用场景
(一)商品推荐场景
在电商平台或者各类商品展示的网页中,商品推荐页面常常会利用到 JavaScript 滚动条滚动事件哦。我们都知道,商品众多的时候,有限的页面空间很难将所有商品一次性展示出来呀。这时候,滚动条滚动事件就派上大用场啦。比如说,我们可以先在 CSS 里设置好页面的基础样式,像 body{padding-bottom: 2000px;} 这样,为页面搭建出一个足够长的大框架,来容纳更多商品信息哦。然后通过 JavaScript 代码去获取页面的一些关键高度值,像用 document.documentElement.scrollHeight 获取页面的总高度,用 document.documentElement.scrollTop 获取从顶部到当前滚动位置的被卷去的高度,以及通过 document.documentElement.clientHeight 拿到页面的可视高度呢。接下来,用总高度减去被卷去的高度再减去可视高度,就能算出页面距离底部的距离啦。再利用 if 语句进行判断,当这个距离达到我们预先设定的某个值的时候,就可以进行相应的操作,比如增加页面的高度,也就是让商品展示区域进一步向下延伸啦,这样用户下拉滚动条的时候,就能不断看到更多的商品内容哦。如此一来,既增加了商品的展示空间,又能让用户按照自己的浏览节奏,方便地查看各种商品,大大提升了用户的浏览体验呢。
(二)固定导航栏与返回顶部功能
当我们浏览一些内容比较长的网页时,会发现有时候随着页面滚动,导航栏却能固定在某个位置,方便我们随时进行各种操作,还有那个返回顶部的按钮,在页面滚下去很多后出现,点击就能快速回到页面顶部,这背后其实都离不开 JavaScript 滚动条滚动事件呀。举个例子呀,先通过 window.addEventListener('scroll',function(){// 执行的具体操作}) 这样的语句来监听整个页面的滚动情况哦。获取元素的时候,比如要获取导航栏元素,像 let navBar = document.querySelector('#navBar') 这样去拿到对应的 DOM 节点,同时还可以获取导航栏的高度等信息,像 let navBarH = navBar.offsetHeight 哦。接着,随着页面滚动,也就是滚动条滚动事件触发时,我们可以获取当前滚动出屏幕的距离,比如用 let offset = document.documentElement.scrollTop 来获取。然后把这个距离和导航栏原本距离页面顶部的距离(事先获取好的哦)进行比较,如果滚动出屏幕的距离大于等于导航栏离顶部的距离了,就通过 navBar.classList.add('fixed') 这样的代码给导航栏添加固定的样式,让它固定在顶部啦。不过要注意哦,导航栏固定后可能会造成内容往上移从而重叠,这时候还得给内容添加一个 margin-top 样式,样式的值通常就是导航栏的高度,像 mainPart.style.marginTop = navBarH + 10 + 'px' 这样去调整呢。而对于返回顶部按钮呀,同样是监听滚动条滚动事件,当页面滚动到一定位置,也就是 scrollTop 值达到我们设定的某个程度时,就让返回顶部按钮显示出来,方便用户点击它,通过代码让页面快速滚动回顶部,给用户操作带来极大的便利哦。
(三)楼层显示切换
在一些内容丰富并且采用分楼层展示的页面里,JavaScript 滚动条滚动事件可以创造出很有意思的交互效果哦。比如在一些大型的资讯网站、楼盘介绍页面等场景中经常会看到呢。页面里会有不同的楼层板块,每个楼层都有各自对应的内容哦。我们可以先获取各个楼层元素,像用 document.querySelectorAll('.layer') 这样的方式把所有楼层元素都选出来存好。然后同样是监听滚动条滚动事件啦,当滚动条滚动到对应楼层区间的时候,通过事件来切换不同楼层内容的显示样式哦。具体来说,随着页面滚动,也就是滚动条滚动事件触发时,获取当前滚动条滚动的距离,比如 var scrollTop = document.documentElement.scrollTop 。接着去遍历每个楼层元素,判断如果某个楼层的 clientHeight + offsetTop 大于当前滚动距离并且当前滚动距离又大于这个楼层的 offsetTop 时,那就意味着滚动到这个楼层的顶部范围啦,这时候就可以通过代码去改变对应的楼层导航按钮等元素的样式,像给对应的楼层导航按钮添加一个 active 类名,表示当前楼层处于激活状态呀,也就是 lis[i].classList.add("active") 这样哦,让用户清晰地知道当前所在楼层呢。要是滚动离开了这个楼层范围,就把这个 active 类名移除掉,切换显示样式,实现了楼层之间随着滚动条滚动的交互切换效果,让用户能更方便地浏览不同楼层的内容哦。
三、获取滚动相关位置信息
(一)scrollLeft 属性
在 JavaScript 中,scrollLeft属性有着重要的作用哦。它可以获取或者设置对象的最左边到对象在当前窗口显示的范围内的左边的距离,简单来讲,就是获取元素被滚动条向左拉动的距离呀,也就是元素内容往左滚出去看不到的那部分距离呢。比如说,当我们在一个内容宽度超过其自身容器宽度的元素中,拉动水平滚动条时,这个属性就能告诉我们元素往左滚动了多远啦。而且值得注意的是,scrollLeft属性是可读写的哦。这意味着我们不仅可以通过它获取当前的滚动距离,还能对它进行赋值操作,从而改变元素的滚动位置呢。举个例子,如果我们有一个div元素,里面的内容比较宽,出现了水平滚动条,我们可以通过代码document.getElementById('yourDivId').scrollLeft = 100;(这里的yourDivId要替换成实际的div元素的id哦),就可以让这个div的内容往左滚动一段距离,将原本看不到的部分显示出来啦,在很多网页的图片轮播、横向内容展示等场景中都会用到这个属性来实现各种滚动效果呢。
(二)scrollTop 属性
scrollTop属性同样很关键呀,它用于获取或者设置对象的最顶部到对象在当前窗口显示的范围内的顶边的距离,也就是元素滚动条被向下拉动的距离哦,通俗地说就是获取被卷去的头部距离,即从顶部到当前滚动位置的距离呢。比如在一个网页页面或者有滚动条的元素中,随着我们滚动鼠标滚轮或者拖动滚动条往下滚动,scrollTop的值就会相应地发生变化啦。它也是可读写的属性哦,在实际应用中,用处可不少呢。像我们常见的制作 “返回顶部” 按钮的功能,就会利用到它啦。通过监听页面的滚动事件,也就是像window.addEventListener('scroll', function() {})这样的代码来监听整个页面滚动情况哦,然后在事件处理函数中获取scrollTop的值,当这个值达到我们预先设定的某个数值时,就让 “返回顶部” 按钮显示出来,方便用户点击后可以通过代码document.documentElement.scrollTop = 0(对于大部分浏览器来说这样设置能让页面快速回到顶部哦,不过有些浏览器可能要使用document.body.scrollTop = 0,实际开发中还可以写兼容代码呢)将页面滚动条快速回到顶部位置呀。再比如在一些内容很长的页面中,根据scrollTop的值来判断当前滚动到了哪个部分,然后去改变对应区域的样式或者加载相关的内容等等,通过它来实现很多有意思的滚动交互效果呢。
四、代码示例展示
(一)简易滚动条创建代码
以下是一个创建简易滚动条的基础代码示例,帮助大家理解其实现逻辑哦。首先,在 HTML 中我们需要有一个元素来作为滚动条出现的容器,比如一个div元素在上述代码中,我们先在 CSS 里定义了.scroll-container这个类对应的元素样式,设置了宽度、高度以及overflow: auto,这样当内容超出设定的高度时就会出现滚动条啦。然后在 JavaScript 部分,通过addEventListener给这个容器添加了scroll事件监听。在事件处理函数中,先是获取了页面的几个关键高度信息,像clientHeight表示可视高度,scrollTop是滚动的距离,scrollHeight则是内容总高度。接着用if语句进行条件判断,比如判断滚动条滚动到接近底部(这里设定为距离底部还有 10 像素左右)的时候打印提示信息,同时还根据滚动条滚动的scrollTop值来改变容器的背景颜色,大于 50 像素时变为浅灰色,否则为白色,以此来展示如何通过不断更新页面高度相关的状态来实现一些滚动条滚动时的交互效果哦。
(二)功能实现代码举例
1. 固定元素显示隐藏代码
以固定顶部导航栏为例,来看下相应的代码实现哦。在这段代码里,首先在 CSS 中定义了导航栏和页面主要内容的基础样式,导航栏设置了背景色、文字颜色以及内边距等,主要内容区域设置了一个较大的高度来模拟长页面哦。然后在 JavaScript 部分,先通过document.getElementById获取到导航栏这个元素,同时定义了prevScrollTop来记录上一次滚动条的滚动位置。接着利用window.addEventListener监听scroll事件,在事件处理函数中获取当前滚动条滚动的位置currentScrollTop。通过比较当前滚动位置和上一次滚动位置,如果页面向上滚动(也就是currentScrollTop < prevScrollTop),就把导航栏往上移隐藏起来(通过设置top为负的导航栏高度值);而当页面向下滚动且滚动距离大于 100px 时(currentScrollTop > 100),就让导航栏固定在顶部(设置top为 0 且position为fixed),并且不断更新prevScrollTop的值,这样就能随着滚动条滚动准确控制导航栏的显示和隐藏啦。
2. 楼层样式切换代码
下面针对楼层显示切换功能展示具体的代码实现哦。在上述代码中,先是在 CSS 里定义了楼层元素.floor的样式,包括高度、边框等,同时设置了有active类名时的背景色变化,还定义了楼层导航栏.floor-nav的位置以及里面列表项的样式哦。然后在 JavaScript 部分,通过document.querySelectorAll获取到所有楼层元素和楼层导航栏的列表项元素。接着利用window.addEventListener监听scroll事件,在事件处理函数中获取当前滚动条滚动的距离scrollTop,然后遍历每个楼层元素,判断如果当前楼层的offsetTop小于scrollTop并且scrollTop小于当前楼层的offsetTop加上clientHeight(也就是滚动到了这个楼层的区间范围),就给对应的楼层元素和楼层导航栏的对应列表项添加active类名,实现样式切换,让用户知道当前所在楼层;要是滚动离开了这个楼层范围,就移除active类名。此外,还给楼层导航栏的每个列表项添加了点击事件监听,当点击某个列表项时,获取对应的目标楼层id,然后通过window.scrollTo方法让页面平滑滚动到目标楼层的顶部位置,方便用户快速切换楼层浏览哦。
五、常见问题及解决办法
(一)移动端原生滚动影响其他元素问题
在移动端进行页面开发时,使用原生滚动有时候会遇到一个比较头疼的问题,那就是当我们在某个区域进行滚动操作时,会连带滚动其他元素,这往往不是我们期望的效果呀。比如说,在一个包含多个模块的移动端页面里,我们只想让其中一个内容较多、有滚动需求的模块能够独立滚动查看详情,可实际操作时,一滚动这个模块,整个页面或者其他相邻模块也跟着一起滚动了,严重影响了用户体验呢。那怎么解决这个问题呢?其实可以通过设置 preventDefault 属性来屏蔽默认事件哦。原理就是原生滚动在移动端默认的行为会影响到相关联的元素,而 preventDefault 能够阻止这种默认行为的发生,让滚动操作仅仅局限在我们期望的那个元素区域内呀。像在使用一些滚动插件(例如 IScroll)时,初始化的时候就可以这样设置:this.myScroll = new IScroll('#wrapper', {preventDefault: true }); 这里的 #wrapper 就是我们想要让其独立滚动的那个元素对应的选择器啦,通过这样的设置,就能避免滚动当前区域的时候连带滚动其他元素了哦。
(二)滚动监听数值获取滞后问题
在给页面绑定滚动监听事件时,可能会碰到获取到的滚动数值是上一次的值这种情况哦,这就导致基于滚动数值去做的一些交互效果出现偏差啦。比如我们想实现一个随着页面滚动,某个元素根据滚动位置实时改变透明度的功能,要是获取的滚动数值不准确、有滞后,那这个元素的透明度变化就会和预期不符,看起来就很奇怪呀。解决这个问题可以尝试更换绑定对象哦。有时候我们可能习惯给 window 或者某个大的容器元素绑定滚动事件,但这样可能会由于一些浏览器的渲染机制或者事件触发顺序等原因,导致获取数值不及时。不妨试着给更具体的、直接关联滚动区域的元素去绑定滚动监听事件呀。另外,还可以考虑使用防抖(debounce)或者节流(throttle)的方法来优化滚动事件的触发频率,减少不必要的重复获取数值等操作,从而提高获取滚动数值的准确性和及时性呢,像下面这样的防抖函数就可以通过合理运用这些思路和方法,就能尽量避免滚动监听数值获取滞后的问题,让页面滚动交互效果更顺畅准确啦。
(三)判断滚动条是否到底部问题
在实际开发中,常常需要判断滚动条是否滚动到底部哦,比如实现 “加载更多” 的功能,当滚动条到底部了,就自动加载新的数据展示给用户呀。那怎么判断滚动条是否到底部呢?这就需要用到 DOM 的几个属性值啦,以纵向滚动条为例(横向滚动条方法类似哦),主要涉及 scrollTop、clientHeight、scrollHeight 这几个属性哦。scrollTop 指的是滚动条在 Y 轴上的滚动距离,也就是从顶部已经滚动了多远;clientHeight 是内容可视区域的高度,就是我们在浏览器窗口中能直接看到的那部分高度;scrollHeight 则是内容可视区域的高度加上溢出(滚动)的距离,也就是整个内容的总高度啦。从这三个属性的含义就能看出来,滚动条到底部的条件就是 scrollTop + clientHeight === scrollHeight 哦。要是判断在某一个元素中的滚动条是否到底部呀,根据类似的思想,将 document.body 等换成特定的元素即可,获取 scrollTop 和 scrollHeight 的方式是一样