最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Scroll to element on page, and then run callback - Stack Overflow

programmeradmin2浏览0评论

I am trying to use jQuery's .animate to scroll to an element on a page, and then execute a callback.

After searching around, I found this function:

function scrollToElement(selector, callback){
    var animation = {scrollTop: $(selector).offset().top};
    $('html,body').animate(animation, 'slow', 'swing', callback);
}

This correctly scrolls to the element defined by 'selector', but callback is called twice (because $('html,body') contains 2 elements).

I tried changing

$('html,body').animate

to:

$(document).animate

and:

$(window).animate

but, neither of those do anything.

I also tried changing the function to this:

$('html').animate(animation, 'slow', 'swing', function(){
    $('body').animate(animation, 'slow', 'swing', callback);
});

but, this made the browser run the 1st animation and then the 2nd, so I had wait for both to run before the callback was ran (I dont't want that).

I figured out that $('body').scrollTop() only works in Chrome, and $('html').scrollTop() only works in Firefox.

So, is there a way (without needing to download a jQuery plugin) for me to scroll to a specific element in both Chrome and Firefox (I don't care about IE), and have a callback executed (once)?

EDIT:

I made a crude fix by making a boolean to check if the callback ran already, and if it was, don't run it again.

function scrollToElement(selector, callback){
    var animation = {scrollTop: $(selector).offset().top};
    var callback_running = false;
    $('html,body').animate(animation, 'slow', 'swing', function(){
        if(typeof callback == 'function' && !callback_running){
            callback_running = true;
            callback();
        }
    });
}

I am trying to use jQuery's .animate to scroll to an element on a page, and then execute a callback.

After searching around, I found this function:

function scrollToElement(selector, callback){
    var animation = {scrollTop: $(selector).offset().top};
    $('html,body').animate(animation, 'slow', 'swing', callback);
}

This correctly scrolls to the element defined by 'selector', but callback is called twice (because $('html,body') contains 2 elements).

I tried changing

$('html,body').animate

to:

$(document).animate

and:

$(window).animate

but, neither of those do anything.

I also tried changing the function to this:

$('html').animate(animation, 'slow', 'swing', function(){
    $('body').animate(animation, 'slow', 'swing', callback);
});

but, this made the browser run the 1st animation and then the 2nd, so I had wait for both to run before the callback was ran (I dont't want that).

I figured out that $('body').scrollTop() only works in Chrome, and $('html').scrollTop() only works in Firefox.

So, is there a way (without needing to download a jQuery plugin) for me to scroll to a specific element in both Chrome and Firefox (I don't care about IE), and have a callback executed (once)?

EDIT:

I made a crude fix by making a boolean to check if the callback ran already, and if it was, don't run it again.

function scrollToElement(selector, callback){
    var animation = {scrollTop: $(selector).offset().top};
    var callback_running = false;
    $('html,body').animate(animation, 'slow', 'swing', function(){
        if(typeof callback == 'function' && !callback_running){
            callback_running = true;
            callback();
        }
    });
}
Share Improve this question edited Feb 16, 2011 at 17:50 gen_Eric asked Feb 16, 2011 at 17:36 gen_Ericgen_Eric 227k42 gold badges303 silver badges342 bronze badges 1
  • I made a crude fix, that checks if the function was already ran. Is there another way to fix this though? – gen_Eric Commented Feb 16, 2011 at 17:48
Add a ment  | 

5 Answers 5

Reset to default 3

I think this should work too

function scrollToElement(selector, callback){
    var animation = {scrollTop: $(selector).offset().top};
    $('html,body').animate(animation, 'slow', 'swing', function() {
        if (typeof callback == 'function') {
            callback();
        }
        callback = null;
    });
}

If you are using jQuery 1.5 (or can upgrade to it), you can use the new $.Deferred syntax.

$.fn.scrollToElement = function(selector, callback) {
    var def = new $.Deferred(),
        el = this;

    $('html, body').animate({scrollTop: $(selector).offset().top}, 'slow', 'swing', def.resolve);

    if (callback) {
        def.promise().done(function(){
            callback.call(el);
        });
    }
};

$('html, body').scrollToElement('#foo', function() {
    alert('done scrolling');
});

Because a deferred object can only be resolved once, you can't have more than one call to the callback.

Have you tried using

$(document.body).animate( ... )

how about using a DIV that stretches over the full document body and do the animation on that DIV instead? you can't be sure how many more browser issues you can find otherwise (i.e. how many more browsers would not animate HTML nor BODY for instance)

You should avoid animating both html and body elements. Your page animation will work correctly on every modern or old browser and the callback will run once (as it should) by the addition of a simple condition in your function.

function scrollToElement(selector, callback){
    var scrollElem='html';
    //animate body for webkit browsers that don't support html animation
    if($.browser.webkit){ 
        scrollElem='body';
    }
    var animation = {scrollTop: $(selector).offset().top};
    $(scrollElem).animate(animation, 'slow', 'swing', callback);
}

Only webkit doesn't support "html" animation, so you change the "scrollElem" variable accordingly. In addition, scrolling a single element (html or body) works much better on older browsers (e.g. previous versions of Opera).

发布评论

评论列表(0)

  1. 暂无评论