纯JavaScript实现滚动添加is-page-scrolled类异常排查
问题描述
我正尝试将一段jQuery代码迁移为纯JavaScript代码。原jQuery代码会在用户滚动到body元素data属性data-page-scrolled-offset指定的偏移量时,为body元素切换is-page-scrolled类;当用户滚动回页面顶部时,该类会被移除。
原可用jQuery代码
var scrolled_page_offset = parseInt( $( 'body' ).data( 'pageScrolledOffset' ) ); var scrolled_page = function() { var scroll_top = window.pageYOffset; $( 'body' ).toggleClass( 'is-page-scrolled', scroll_top > scrolled_page_offset ); }; $( window ).on( 'scroll', function() { scrolled_page(); } ); scrolled_page();
无法正常工作的纯JavaScript代码
var scrolled_page_offset = parseInt( document.body.dataset.pageScrolledOffset ); var scrolled_page = function() { var scroll_top = window.pageYOffset; if ( scroll_top > scrolled_page_offset ) { document.body.classList.toggle( 'is-page-scrolled' ); } }; window.addEventListener( 'scroll', function() { scrolled_page(); } ); scrolled_page();
我编写的纯JavaScript代码无法正常工作,用户向下滚动页面时,is-page-scrolled类会被间歇性反复切换。请问我哪里出错了?
问题原因与修复方案
核心错误
你混淆了jQuery的toggleClass和原生JS的classList.toggle的行为差异:
- jQuery的
toggleClass(className, state)第二个参数是布尔值,用来强制决定类的添加/移除:true就添加,false就移除,不会反复切换状态。 - 你写的原生代码里,只在
scroll_top > scrolled_page_offset时调用classList.toggle('is-page-scrolled'),这意味着每次滚动触发这个条件时,类都会被切换一次(有则删,无则加),所以会出现间歇性反复切换的问题。同时,你完全没处理滚动回偏移量以内的情况,类根本不会被移除。
修复方案
有两种写法可以实现和原jQuery一致的效果:
方案1:使用classList.add和classList.remove(兼容性最好)
var scrolled_page_offset = parseInt(document.body.dataset.pageScrolledOffset); var scrolled_page = function() { var scroll_top = window.pageYOffset; if (scroll_top > scrolled_page_offset) { document.body.classList.add('is-page-scrolled'); } else { document.body.classList.remove('is-page-scrolled'); } }; window.addEventListener('scroll', scrolled_page); scrolled_page();
方案2:使用原生toggle的第二个参数(现代浏览器支持)
原生classList.toggle其实也支持第二个布尔参数,和jQuery的逻辑完全一致:
var scrolled_page_offset = parseInt(document.body.dataset.pageScrolledOffset); var scrolled_page = function() { var scroll_top = window.pageYOffset; // 第二个参数为true时添加类,false时移除类 document.body.classList.toggle('is-page-scrolled', scroll_top > scrolled_page_offset); }; window.addEventListener('scroll', scrolled_page); scrolled_page();
额外优化
滚动事件触发频率很高,建议加上防抖优化,避免频繁操作DOM:
var scrolled_page_offset = parseInt(document.body.dataset.pageScrolledOffset); var scrolled_page = function() { var scroll_top = window.pageYOffset; document.body.classList.toggle('is-page-scrolled', scroll_top > scrolled_page_offset); }; // 防抖函数 function debounce(func, delay = 100) { let timer; return function() { clearTimeout(timer); timer = setTimeout(func, delay); }; } window.addEventListener('scroll', debounce(scrolled_page)); scrolled_page();
内容的提问来源于stack exchange,提问作者leemon
相关产品推荐
相关产品推荐

