如何保留location.href逻辑同时不干扰自定义JS平滑滚动效果
问题原因
直接给location.href赋值带锚点hash的地址时,浏览器会原生触发瞬时跳转到对应锚点元素的默认行为,这个行为会立即中断后续window.scrollTo执行的平滑滚动过程,直接把页面定位到锚点位置,导致自定义平滑效果失效。
可行方案(无需删除URL更新逻辑、无需依赖CSS平滑滚动)
方案1:使用history.replaceState更新URL(推荐)
history.replaceState只会更新浏览器地址栏的URL显示,不会触发页面刷新、不会触发默认锚点滚动,完全不会干扰后续的自定义平滑滚动逻辑,同时能保留你需要的URL区块标识功能。
你只需要把原代码中给location.href赋值的部分替换掉即可,其余逻辑完全不用修改:
document.getElementById('link_no' + (i + 1)).classList.add('active-link'); // 替换原有的location.href赋值逻辑 // let currentLocation = location.href; // currLocationArray = currentLocation.split("#"); // currentLocation = currLocationArray[0]; // currentLocation += `#section${i+1}`; // location.href = currentLocation; history.replaceState(null, '', `#section${i+1}`); // 以下自定义滚动逻辑保持原样即可 let sectionOfI = document.getElementById(`section${i+1}`); let scrollArea = getOffset(sectionOfI); scrollEventNew(scrollArea.top,e);
这个方案的优势:
- 地址栏正常展示
#section1/#section2这类区块标识,支持用户复制链接分享、刷新页面定位 - 无任何默认副作用,不会打断JS平滑滚动
- 代码改动量极小,不需要调整现有滚动函数
方案2:临时移除锚点id(极端兼容场景兜底)
如果需要兼容不支持History API的极老旧浏览器,可以通过临时移除目标区块id的方式,让浏览器找不到对应锚点、无法触发默认跳转,等URL更新完成后再恢复id,最后执行自定义滚动:
document.getElementById('link_no' + (i + 1)).classList.add('active-link'); let sectionOfI = document.getElementById(`section${i+1}`); // 临时暂存并移除目标区块的id const originId = sectionOfI.id; sectionOfI.removeAttribute('id'); // 更新URL的hash location.hash = `#section${i+1}`; // 立即恢复id sectionOfI.id = originId; // 执行自定义平滑滚动 let scrollArea = getOffset(sectionOfI); scrollEventNew(scrollArea.top,e);
注意:不要直接使用
location.hash = xxx的写法更新锚点,该写法和给location.href赋值带hash的地址效果一致,都会触发默认瞬时滚动,打断平滑效果。
内容的提问来源于stack exchange,提问作者srohome
相关产品推荐
相关产品推荐

