You need to enable JavaScript to run this app. 如何实现单页网站锚点间定点滚动 修复JS连续跨多锚点问题
优惠活动
大模型
产品
解决方案
定价
更多

如何实现单页网站锚点间定点滚动 修复JS连续跨多锚点问题

单页锚点固定滚动修复方案

核心修改逻辑

  • 原有代码滚动锁生效时间与动画时长不匹配,导致单次滚动触发多次锚点跳转,本次修改采用「动画结束回调解锁」机制,保证滚动动画完全结束前不会响应新的滚轮操作
  • 修复了变量作用域问题,避免边界场景下锚点定位错误
  • 移除了冗余的无效分支逻辑,避免代码冲突

修复后完整代码

// 引入jQuery后执行以下代码
$(function() {
    var isScrolling = false;
    var scrollDuration = 750;
    var scrollOffset = 0; // 若有固定头部可修改为头部高度,避免锚点被遮挡

    // 监听滚轮事件
    $(document).on('mousewheel DOMMouseScroll', function(event) {
        event.preventDefault();
        // 滚动过程中直接拦截新的滚轮操作
        if(isScrolling) return;
        isScrolling = true;

        // 获取滚轮方向
        var wheelDelta = event.originalEvent.wheelDelta || -event.originalEvent.detail;
        // 获取所有区块顶部的无href锚点
        var anchorList = $("a:not([href])");
        var targetIndex = 0;

        if(wheelDelta < 0) {
            // 向下滚动:匹配下一个锚点
            for(var i = 0; i < anchorList.length; i++) {
                var rectTop = anchorList[i].getClientRects()[0].top;
                if(rectTop >= 70) {
                    targetIndex = i;
                    break;
                }
                // 到达最后一个锚点时停住
                if(i === anchorList.length -1) targetIndex = anchorList.length -1;
            }
        } else {
            // 向上滚动:匹配上一个锚点
            for(var i = anchorList.length - 1; i >= 0; i--) {
                var rectTop = anchorList[i].getClientRects()[0].top;
                if(rectTop < -70) {
                    targetIndex = i;
                    break;
                }
                // 到达第一个锚点时停住
                if(i === 0) targetIndex = 0;
            }
        }

        // 执行滚动动画
        $("html, body").animate({ 
            scrollTop: $(anchorList[targetIndex]).offset().top - scrollOffset 
        }, scrollDuration, 'easeInOutQuad', function() {
            // 动画结束后解锁
            isScrolling = false;
        });
    });
});

// 原有动画缓动扩展保留即可
jQuery.easing.jswing=jQuery.easing.swing;jQuery.extend(jQuery.easing,{def:"easeOutQuad",swing:function(e,f,a,h,g){return jQuery.easing[jQuery.easing.def](e,f,a,h,g)},easeInQuad:function(e,f,a,h,g){return h*(f/=g)*f+a},easeOutQuad:function(e,f,a,h,g){return -h*(f/=g)*(f-2)+a},easeInOutQuad:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f+a}return -h/2*((--f)*(f-2)-1)+a},easeInCubic:function(e,f,a,h,g){return h*(f/=g)*f*f+a},easeOutCubic:function(e,f,a,h,g){return h*((f=f/g-1)*f*f+1)+a},easeInOutCubic:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f*f+a}return h/2*((f-=2)*f*f+2)+a},easeInQuart:function(e,f,a,h,g){return h*(f/=g)*f*f*f+a},easeOutQuart:function(e,f,a,h,g){return -h*((f=f/g-1)*f*f*f-1)+a},easeInOutQuart:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f*f*f+a}return -h/2*((f-=2)*f*f*f-2)+a},easeInQuint:function(e,f,a,h,g){return h*(f/=g)*f*f*f*f+a},easeOutQuint:function(e,f,a,h,g){return h*((f=f/g-1)*f*f*f*f+1)+a},easeInOutQuint:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f*f*f*f+a}return h/2*((f-=2)*f*f*f*f+2)+a},easeInSine:function(e,f,a,h,g){return -h*Math.cos(f/g*(Math.PI/2))+h+a},easeOutSine:function(e,f,a,h,g){return h*Math.sin(f/g*(Math.PI/2))+a},easeInOutSine:function(e,f,a,h,g){return -h/2*(Math.cos(Math.PI*f/g)-1)+a},easeInExpo:function(e,f,a,h,g){return(f==0)?a:h*Math.pow(2,10*(f/g-1))+a},easeOutExpo:function(e,f,a,h,g){return(f==g)?a+h:h*(-Math.pow(2,-10*f/g)+1)+a},easeInOutExpo:function(e,f,a,h,g){if(f==0){return a}if(f==g){return a+h}if((f/=g/2)<1){return h/2*Math.pow(2,10*(f-1))+a}return h/2*(-Math.pow(2,-10*--f)+2)+a},easeInCirc:function(e,f,a,h,g){return -h*(Math.sqrt(1-(f/=g)*f)-1)+a},easeOutCirc:function(e,f,a,h,g){return h*Math.sqrt(1-(f=f/g-1)*f)+a},easeInOutCirc:function(e,f,a,h,g){if((f/=g/2)<1){return -h/2*(Math.sqrt(1-f*f)-1)+a}return h/2*(Math.sqrt(1-(f-=2)*f)+1)+a},easeInElastic:function(f,h,e,l,k){var i=1.70158;var j=0;var g=l;if(h==0){return e}if((h/=k)==1){return e+l}if(!j){j=k*0.3}if(g<Math.abs(l)){g=l;var i=j/4}else{var i=j/(2*Math.PI)*Math.asin(l/g)}return -(g*Math.pow(2,10*(h-=1))*Math.sin((h*k-i)*(2*Math.PI)/j))+e},easeOutElastic:function(f,h,e,l,k){var i=1.70158;var j=0;var g=l;if(h==0){return e}if((h/=k)==1){return e+l}if(!j){j=k*0.3}if(g<Math.abs(l)){g=l;var i=j/4}else{var i=j/(2*Math.PI)*Math.asin(l/g)}return g*Math.pow(2,-10*h)*Math.sin((h*k-i)*(2*Math.PI)/j)+l+e},easeInOutElastic:function(f,h,e,l,k){var i=1.70158;var j=0;var g=l;if(h==0){return e}if((h/=k/2)==2){return e+l}if(!j){j=k*(0.3*1.5)}if(g<Math.abs(l)){g=l;var i=j/4}else{var i=j/(2*Math.PI)*Math.asin(l/g)}if(h<1){return -0.5*(g*Math.pow(2,10*(h-=1))*Math.sin((h*k-i)*(2*Math.PI)/j))+e}return g*Math.pow(2,-10*(h-=1))*Math.sin((h*k-i)*(2*Math.PI)/j)*0.5+l+e},easeInBack:function(e,f,a,i,h,g){if(g==undefined){g=1.70158}return i*(f/=h)*f*((g+1)*f-g)+a},easeOutBack:function(e,f,a,i,h,g){if(g==undefined){g=1.70158}return i*((f=f/h-1)*f*((g+1)*f+g)+1)+a},easeInOutBack:function(e,f,a,i,h,g){if(g==undefined){g=1.70158}if((f/=h/2)<1){return i/2*(f*f*(((g*=(1.525))+1)*f-g))+a}return i/2*((f-=2)*f*(((g*=(1.525))+1)*f+g)+2)+a},easeInBounce:function(e,f,a,h,g){return h-jQuery.easing.easeOutBounce(e,g-f,0,h,g)+a},easeOutBounce:function(e,f,a,h,g){if((f/=g)<(1/2.75)){return h*(7.5625*f*f)+a}else{if(f<(2/2.75)){return h*(7.5625*(f-=(1.5/2.75))*f+0.75)+a}else{if(f<(2.5/2.75)){return h*(7.5625*(f-=(2.25/2.75))*f+0.9375)+a}else{return h*(7.5625*(f-=(2.625/2.75))*f+0.984375)+a}}}},easeInOutBounce:function(e,f,a,h,g){if(f<g/2){return jQuery.easing.easeInBounce(e,f*2,0,h,g)*0.5+a}return jQuery.easing.easeOutBounce(e,f*2-g,0,h,g)*0.5+h*0.5+a}});

可调整参数说明

  • scrollDuration:滚动动画时长,单位毫秒,可根据交互需求调整
  • scrollOffset:滚动偏移值,页面有固定悬浮头部时可设置为头部高度,避免锚点内容被头部遮挡
  • 锚点判定阈值70可根据实际页面效果调整,数值越大锚点匹配的容错范围越高

内容的提问来源于stack exchange,提问作者Karan Vij

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 12:24:02