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

IT技术 javascript jquery
2021-01-16 17:53:18

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

6个回答

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

$("html, body").animate({ scrollTop: "300px" });
为什么你需要htmlbody这里有一些见解:stackoverflow.com/questions/2123690/...,但这不是一个完整的答案。
2021-03-20 17:53:18
webkit 使用 body,firefox 使用 html。
2021-03-25 17:53:18
仅供参考:如果<html>overflow-x:hidden;这个动画将不起作用。(可能不适用于overflow-y:hidden, 和overflow:hidden,但我还没有测试过。
2021-03-26 17:53:18
非常好..不需要为此使用插件。
2021-03-31 17:53:18
我认为body今年早些时候在 Chrome 中工作过,但现在必须是html.
2021-04-12 17:53:18

尼克的回答很有效。在 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');
            }
        }
    }
);
是的,在这种情况下它只会弹出一次。如果您需要重复动画,您可以将 completeCalled 变量设为执行动画函数的回调函数的局部变量。这样,当您单击时它仍然只会弹出一次,但是当您再次单击时它会再次弹出(仅一次)。
2021-03-15 17:53:18
问题是,为什么要为 'html, body' 而不仅仅是 'body' 设置动画?
2021-03-28 17:53:18
但在这种情况下,它只会弹出一次,如果必须重复调用它(按钮上的单击事件)还是我错过了什么?
2021-04-02 17:53:18
因为根据您使用的浏览器,您可以为 body 或 html 设置动画。通过为两者设置动画,您可以覆盖更多浏览器。
2021-04-05 17:53:18
为了防止双重回调函数触发,您可以die()live()函数调用之前使用函数这保证您的live()处理程序只会被调用一次。
2021-04-10 17:53:18

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/

就像 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 属性总是返回零。相反,我找到了一种方法,可以在每次动画执行时使用 promise 执行单个回调。

$('html, body')
    .animate({ scrollTop: 100 })
    .promise()
    .then(function(){
        // callback code here
    })
});
这需要更多的赞成票。我以前从未见过用于此的Promise,这是我每隔几个月就会搜索一次的东西。正如艾伦所说,天才。
2021-03-22 17:53:18
在这里使用 promise() 是天才。
2021-03-27 17:53:18

我有我认为比$('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);
                    }
                }
            }
        );
    }
}