如何无滚动修改location.hash,基于href匹配ID简化单页区块显隐
通用无重复判断的hash区块切换实现
核心逻辑
彻底放弃逐hash写分支判断的写法,所有操作通过通用规则完成:
- 直接把地址栏的hash值(去掉#号)当做目标DOM元素的id进行匹配,不需要硬编码每个hash对应的区块
- 切换激活状态时,先批量清除所有区块的active类,再给匹配到的目标元素加上active类,完全不需要为每个区块重复写移除类的代码
- 切换完成后强制还原滚动位置,抵消浏览器默认的hash跳转滚动行为
完整可直接运行的代码
通用JS逻辑
// 统一配置所有参与切换的区块选择器,后续新增页面只需要给区块加上对应类即可,逻辑无需改动 const SECTION_SELECTOR = '.page-section'; function updateActiveByHash() { // 提取hash值,空hash默认展示home区块 const targetId = window.location.hash.slice(1) || 'home'; // 批量清除所有区块的激活状态 document.querySelectorAll(SECTION_SELECTOR).forEach(section => { section.classList.remove('active'); }); const targetEl = document.getElementById(targetId); if (targetEl) { targetEl.classList.add('active'); // 抵消浏览器默认的hash自动滚动,保持当前滚动位置不变 window.scrollTo({ top: window.scrollY, behavior: 'instant' }); } else { // 兜底:hash对应区块不存在时,自动切回默认首页 window.location.hash = 'home'; } } // 监听hash变化 + 首次加载时初始化激活状态 window.addEventListener('hashchange', updateActiveByHash); window.addEventListener('DOMContentLoaded', updateActiveByHash);
简化CSS
a { padding: 20px; margin-right: 5px; } /* 统一控制所有区块的显隐,不需要逐一声明每个id的样式 */ .page-section { display: none; } .page-section.active { display: block; }
适配的HTML结构
<a href='#home'>home</a> <a href='#projects'>projects</a> <a href='#skills'>skills</a> <a href='#about'>about</a> <div id='home' class='page-section active'> <p>content home.</p> </div> <div id='projects' class='page-section'> <p>content projects.</p> </div> <div id='skills' class='page-section'> <p>content skills.</p> </div> <div id='about' class='page-section'> <p>content about.</p> </div>
关键特性
- 零重复代码:不管有多少个区块,不管后续新增多少页面,逻辑完全不需要修改
- 自动匹配:导航链接的href值和区块id保持一致即可触发切换,不需要在JS里维护任何映射关系
- 无滚动跳变:hash变化时不会触发浏览器自动滚动到目标区块的默认行为,始终保持用户当前的浏览位置
- 异常兼容:手动输入不存在的hash时会自动回退到默认展示页,不会出现全页面空白的问题
内容的提问来源于stack exchange,提问作者CodingT
相关产品推荐
相关产品推荐

