【问题标题】:Building an animated menu with Jquery that responds to page scrolling使用 Jquery 构建响应页面滚动的动画菜单
【发布时间】:2014-11-30 12:29:10
【问题描述】:

对不起,糟糕的标题,但我不确定如何描述我正在尝试构建的内容。我正在使用我在这个网站上找到的一些代码,基本上我想做的是构建一个左手导航菜单,当用户滚动到它时突出显示相应的部分。

$(document).ready(function() {
  var topRange = 200, // measure from the top of the viewport to X pixels down
    edgeMargin = 20, // margin above the top or margin from the end of the page
    animationTime = 600, // time in milliseconds
    contentTop = []; //array of sidebar links
  $('nav ul').append('<div id="slider"></div>');

  var sliderTop = $("nav ul li a").eq(0).parent().position().top;
  var sliderLeft = $("nav ul li a").eq(0).parent().position().left;
  var sliderHeight = $("nav ul li a").eq(0).parent().outerHeight();

  $('#slider').css({
    'height': sliderHeight,
    'left': sliderLeft,
    'top': sliderTop,
    'width': '100%'
  });


  // Stop animated scroll if the user does something
  $('html,body').bind('scroll mousedown DOMMouseScroll mousewheel keyup', function(e) {
    if (e.which > 0 || e.type == 'mousedown' || e.type == 'mousewheel') {
      $('html,body').stop();
    }
  })

  // Set up content an array of locations
  $('#sidebar').find('a').each(function() {
    contentTop.push($($(this).attr('href')).offset().top);
  })

  // Animate menu scroll to content
  $('#sidebar').find('a').click(function() {
    var sel = this,
      newTop = Math.min(contentTop[$('#sidebar a').index($(this))], $(document).height() - $(window).height()); // get content top or top position if at the document bottom
    $('html,body').stop().animate({
      'scrollTop': newTop
    }, animationTime, function() {
      window.location.hash = $(sel).attr('href');
    });
    return false;
  })

  //scroll function
  function scroller() {
      var winTop = $(window).scrollTop(),
        bodyHt = $(document).height(),
        vpHt = $(window).height() + edgeMargin; // viewport height + margin
      $.each(contentTop, function(i, loc) {
        if ((loc > winTop - edgeMargin && (loc < winTop + topRange || (winTop + vpHt) >= bodyHt))) {

          //animate slider
          x = $("#sidebar li").eq(i).position();
          $("#slider").animate({
            top: (x.top)
          }, 100);
        }
      })
    }
    //scroll event handler
  $(window).scroll(scroller)
})

我大部分都在工作,但是当您实际单击菜单上的链接时,动画赶上实际滚动速度非常慢。我理解为什么会发生这种情况,因为它在到达每个部分后一次更新一个位置,但我想知道是否有办法让这个动画更快,更流畅。我已经附上了我的代码,提前感谢您的帮助!

http://jsfiddle.net/jamesmyers/6mbmq1pe/

【问题讨论】:

    标签: javascript jquery animation navigation scroll


    【解决方案1】:

    通过暂时分离scroll处理程序并直接滚动滑块,您将获得更好的滑块动画效果,animationTime与主动画相同。

    为此,您还需要:

    • 命名空间滚动事件.nav,以允许安全使用.off()
    • stop()“如果用户做某事”块中的滑块动画

    我还在 contentTop#slider 的设置方式中加入了一些效率节省,但这些实际上并不是必需的。

    $(document).ready(function() {
        var topRange = 200, // measure from the top of the viewport to X pixels down
            edgeMargin = 20, // margin above the top or margin from the end of the page
            animationTime = 600, // time in milliseconds
            contentTop, //array of sidebar links
            navLinkWrapper = $("nav ul li a").eq(0).parent();
    
        var $slider = $("<div id=\"slider\" />").css({
            'height': navLinkWrapper.outerHeight(),
            'left': navLinkWrapper.position().left,
            'top': navLinkWrapper.position().top,
            'width': '100%'
        }).appendTo($('nav ul'));
    
        // Stop animated scroll if the user does something
        $('html,body').on('scroll mousedown DOMMouseScroll mousewheel keyup', function(e) {
            if (e.which > 0 || e.type == 'mousedown' || e.type == 'mousewheel') {
                $('html,body').stop();
                $slider.stop(); //<<<<<<<
            }
        });
    
        // Set up content an array of locations
        contentTop = $('#sidebar a').map(function() {
            return $($(this).attr('href')).offset().top;
        });
    
        // Animate menu scroll to content
        $('#sidebar a').on('click', function(e) {
            e.preventDefault();
            $(window).off('scroll.nav', scroller); //<<<<<<<
            $slider.stop().animate({ //<<<<<<<
                top: ($(this).closest("li").position().top) //<<<<<<<
            }, animationTime); //<<<<<<<
            var sel = this,
                newTop = Math.min(contentTop[$('#sidebar a').index($(this))], $(document).height() - $(window).height()); // get content top or top position if at the document bottom
            $('html,body').stop().animate({
                'scrollTop': newTop
            }, animationTime, function() {
                window.location.hash = $(sel).attr('href');
                $(window).on('scroll.nav', scroller); //<<<<<<<
            });
        });
    
        //scroll function
        function scroller() {
            var winTop = $(window).scrollTop(),
                bodyHt = $(document).height(),
                vpHt = $(window).height() + edgeMargin; // viewport height + margin
            $.each(contentTop, function(i, loc) {
                if ((loc > winTop - edgeMargin && (loc < winTop + topRange || (winTop + vpHt) >= bodyHt))) {
                    //animate slider
                    $slider.animate({
                        top: ($("#sidebar li").eq(i).position().top)
                    }, 100);
                }
            });
        }
        //scroll event handler
        $(window).on('scroll.nav', scroller); //<<<<<<<
    });
    

    Updated fiddle

    【讨论】:

    • 非常感谢!这很好用,我真的很感激。感谢您清楚地标记您的更改,这真的有助于我学习。干杯。
    • 很抱歉再次打扰您,但我注意到添加这些更改后,有时滚动滑块会落后。有什么办法可以纠正吗?
    • 我没有看到这一点,但实际上还有一个更糟糕的问题,即滑块动画在“如果用户做了某事”条件下停止了。解决方案相当棘手 - jsfiddle.net/6mbmq1pe/3
    • 感谢您的回复。我也注意到了这一点,即使是你最新的小提琴。我会以错误的方式解决这个问题吗?有没有更简单的方法来实现这种效果?
    • 很有可能,尽管我认为这只是一个细化的问题。继续努力,直到你解决了这些错误。
    猜你喜欢
    • 1970-01-01
    • 2010-11-24
    • 1970-01-01
    • 1970-01-01
    • 2021-04-04
    • 2018-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多