滚动到锚点时URL更新对应hash,回到顶部时自动移除锚点hash如何实现
滚动同步锚点Hash的代码修改方案
原有代码的核心问题是仅在锚点可见时更新hash,没有对「无可见锚点」的场景做处理,同时遍历锚点时如果多个锚点同时可见会反复触发hash写入,以下是修改后的完整可运行代码:
function isElementInViewport (el) { // 兼容jQuery元素入参 if (typeof jQuery === "function" && el instanceof jQuery) { el = el[0]; } var rect = el.getBoundingClientRect(); return ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth) ); } // 点击锚点滚动逻辑 $(".anchor").click(function (e) { e.preventDefault(); var section = this.href; var sectionClean = section.substring(section.indexOf("#")); $("html, body").animate({ scrollTop: $(sectionClean).offset().top }, 1000, function () { window.location.hash = sectionClean; }); }); // 滚动事件监听 $(document).on("scroll", function() { console.log("onscroll event fired..."); let visibleAnchorExists = false; let currentHash = window.location.hash; // 遍历所有锚点元素 $(".anchor").each(function (idx, el) { if (isElementInViewport(el)) { visibleAnchorExists = true; const targetHash = "#" + $(el).attr("id"); // 仅当hash变化时才更新,避免重复写入历史 if (window.history.pushState && targetHash !== currentHash) { window.history.pushState(null, null, targetHash); currentHash = targetHash; } } }); // 无可见锚点时清空hash if (!visibleAnchorExists && currentHash !== "" && window.history.pushState) { // 用pushState修改地址,不会触发页面滚动 window.history.pushState(null, null, window.location.pathname + window.location.search); } });
关键修改说明
- 新增
visibleAnchorExists变量统计视口内是否存在可见锚点,遍历所有锚点后统一判断是否需要清空hash - 新增hash变化校验,只有和当前地址栏hash不一致时才执行更新,避免大量重复历史记录生成
- 清空hash时使用
pushState仅修改地址栏内容,不会触发页面跳转或滚动,和原有更新逻辑的行为保持一致
内容的提问来源于stack exchange,提问作者Kiki
相关产品推荐
相关产品推荐

