是否可以使用 jQuery 为 scrollTop 设置动画?

Posted

技术标签:

【中文标题】是否可以使用 jQuery 为 scrollTop 设置动画?【英文标题】:Is it possible to animate scrollTop with jQuery? 【发布时间】:2021-07-05 02:25:19 【问题描述】:

我想流畅地向下滚动。我不想为此编写一个函数 - 特别是如果 jQuery 已经有一个。

【问题讨论】:

【参考方案1】:

您可以只使用.animate() scrollTop 属性,如下所示:

$("html, body").animate( scrollTop: "300px" );

【讨论】:

非常好..不需要为此使用插件。 为什么需要htmlbody?这里有一些见解:***.com/questions/2123690/…,但这不是一个完整的答案。 webkit使用body,firefox使用html。 仅供参考:如果<html> 具有overflow-x:hidden;,则此动画将不起作用。 (可能不适用于overflow-y:hiddenoverflow:hidden,但我没有测试过。 我认为 body 今年早些时候在 Chrome 中工作,但现在它必须是 html【参考方案2】:

尼克的回答效果很好。在 animate() 调用中指定 complete() 函数时要小心,因为它会被执行两次,因为您声明了两个选择器(html 和 body)。

$("html, body").animate(
     scrollTop: "300px" ,
    
        complete : function()
            alert('this alert will popup twice');
        
    
);

以下是避免双重回调的方法。

var completeCalled = false;
$("html, body").animate(
     scrollTop: "300px" ,
    
        complete : function()
            if(!completeCalled)
                completeCalled = true;
                alert('this alert will popup once');
            
        
    
);

【讨论】:

问题是,为什么要为 'html, body' 而不仅仅是 'body' 制作动画? 因为根据您使用的浏览器,您可以为 body 或 html 设置动画。通过为 BOTH 制作动画,您可以覆盖更多浏览器。 但是在这种情况下它只会弹出一次,如果它必须被重复调用(点击按钮上的事件)或者我错过了什么? 是的,在这种情况下它只会弹出一次。如果您需要重复动画,您可以将 completeCalled 变量设置为执行动画函数的回调函数的本地变量。这样,当您单击时它仍然只会弹出一次,但当您再次单击时它会再次弹出(仅一次)。 为了防止双重回调函数触发,您可以在 live() 函数调用之前使用 die() 函数。这保证了您的 live() 处理程序只会被调用一次。【参考方案3】:

Nick 的回答效果很好,默认设置也不错,但是您可以通过完成所有可选设置来更全面地控制滚动。

这是它在 API 中的样子:

.animate( properties [, duration] [, easing] [, complete] )

所以你可以这样做:

.animate( 
    scrollTop:'300px',
    300,
    swing,
    function() 
       alert(animation complete! - your custom code here!); 
        
    )

这里是 jQuery .animate 函数 api 页面:http://api.jquery.com/animate/

【讨论】:

【参考方案4】:

就像 Kita 提到的那样,当您在“html”和“body”上制作动画时,会触发多个回调。我更喜欢使用一些基本的特征检测并且只为单个对象的 scrollTop 属性设置动画,而不是同时设置动画并阻止后续回调。

在另一个线程上接受的答案提供了一些关于我们应该尝试为哪个对象的 scrollTop 属性设置动画的见解:pageYOffset Scrolling and Animation in IE8

// UPDATE: don't use this... see below
// only use 'body' for IE8 and below
var scrollTopElement = (window.pageYOffset != null) ? 'html' : 'body';

// only animate on one element so our callback only fires once!
$(scrollTopElement).animate( 
        scrollTop: '400px' // vertical position on the page
    ,
    500, // the duration of the animation 
    function()        
        // callback goes here...
    )
);

更新 - - -

上述特征检测尝试失败。似乎没有一种单行的方式来做到这一点,因为 webkit 类型的浏览器 pageYOffset 属性在有 doctype 时总是返回零。 相反,我找到了一种方法,可以在每次动画执行时使用 Promise 进行一次回调。

$('html, body')
    .animate( scrollTop: 100 )
    .promise()
    .then(function()
        // callback code here
    )
);

【讨论】:

在这里使用 promise() 是天才。 这需要更多的支持。我以前从未见过 promise 用于此目的,而这是我每隔几个月就会寻找的东西。正如艾伦所说,天才。【参考方案5】:

我认为比$('html, body') hack 更好的解决方案。

这不是单行的,但我对$('html, body') 的问题是,如果您在动画期间记录$(window).scrollTop(),您会看到该值在整个地方跳跃,有时跳跃数百像素(虽然我在视觉上看不到类似的事情发生)。我需要该值是可预测的,这样如果用户在自动滚动期间抓住滚动条或旋转鼠标滚轮,我就可以取消动画。

这是一个可以平滑滚动的函数:

function animateScrollTop(target, duration) 
    duration = duration || 16;
    var scrollTopProxy =  value: $(window).scrollTop() ;
    if (scrollTopProxy.value != target) 
        $(scrollTopProxy).animate(
             value: target , 
             duration: duration, step: function (stepValue) 
                var rounded = Math.round(stepValue);
                $(window).scrollTop(rounded);
            
        );
    

下面是一个更复杂的版本,它将在用户交互时取消动画,并重新触发直到达到目标值,这在尝试立即设置 scrollTop 时很有用(例如,简单地调用 $(window).scrollTop(1000) — 根据我的经验,这在大约 50% 的情况下都无法正常工作。)

function animateScrollTop(target, duration) 
    duration = duration || 16;

    var $window = $(window);
    var scrollTopProxy =  value: $window.scrollTop() ;
    var expectedScrollTop = scrollTopProxy.value;

    if (scrollTopProxy.value != target) 
        $(scrollTopProxy).animate(
             value: target ,
            
                duration: duration,

                step: function (stepValue) 
                    var roundedValue = Math.round(stepValue);
                    if ($window.scrollTop() !== expectedScrollTop) 
                        // The user has tried to scroll the page
                        $(scrollTopProxy).stop();
                    
                    $window.scrollTop(roundedValue);
                    expectedScrollTop = roundedValue;
                ,

                complete: function () 
                    if ($window.scrollTop() != target) 
                        setTimeout(function () 
                            animateScrollTop(target);
                        , 16);
                    
                
            
        );
    

【讨论】:

【参考方案6】:

在其他示例中,我遇到了在页面刷新后动画总是从页面顶部开始的问题。

我通过不直接为 css 设置动画来解决此问题,而是在每个步骤中调用 window.scrollTo();

$(myScrollTop:window.pageYOffset).animate(myScrollTop:300, 
  duration: 600,
  easing: 'swing',
  step: function(val) 
    window.scrollTo(0, val);
  
);

这也解决了 htmlbody 的问题,因为它使用的是跨浏览器 javascript

请查看http://james.padolsey.com/javascript/fun-with-jquerys-animate/,了解有关您可以使用 jQuery 的动画功能做什么的更多信息。

【讨论】:

【参考方案7】:

您可以将 jQuery 动画用于具有特定持续时间的滚动页面:

$("html, body").animate(scrollTop: "1024px", 5000);

其中 1024px 是滚动偏移量,5000 是动画的持续时间(以毫秒为单位)。

【讨论】:

很好的答案!很高兴您包括了持续时间选项。只是想补充一点 $("html, body").animate(scrollTop: 1024, 5000); 也可以。【参考方案8】:

试试scrollTo 插件。

【讨论】:

scrollTo 似乎不再是该站点的项目。 实现这一点的代码非常简单。你为什么要添加一个插件来做一些你可以用一行代码做的事情? 四年前没那么简单.. :)【参考方案9】:
$(".scroll-top").on("click", function(e)
   e.preventDefault();
   $("html, body").animate(scrollTop:"0",600);
);

【讨论】:

【参考方案10】:

如果你想在页面末尾向下移动(这样你就不需要向下滚动到底部),你可以使用:

$('body').animate( scrollTop: $(document).height() );

【讨论】:

【参考方案11】:

但如果你真的想在滚动时添加一些动画,你可以试试我的简单插件 (AnimateScroll),它目前支持 30 多种缓动样式

【讨论】:

【参考方案12】:

跨浏览器代码为:

$(window).scrollTop(300); 

它没有动画,但无处不在

【讨论】:

我正在寻找一种方法“使用 jQuery 为 scrollTop 设置动画?” “没有动画”的答案不是答案。

以上是关于是否可以使用 jQuery 为 scrollTop 设置动画?的主要内容,如果未能解决你的问题,请参考以下文章

是否有更好的方法在 iPhone 的 Safari 中滚动页面(使用 jQuery)(scrollTop 无法正常工作)

使用 jQuery 方法扩展 Zepto.js?滚动顶部()

scrollTop 在 Android 手机中不起作用

使用原生js的scrollTop,刷新进入页面定位到某一个dom元素

jQuery动画效果animate和scrollTop结合使用实例

JQuery元素滚动定位及获取元素的scrollTop,clientHeight,scrollHeight