Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
820 views
in Technique[技术] by (71.8m points)

jquery - Accounting for a fixed header with animate.scrolltop and (target).offset().top;

This should be a pretty basic question, but i've thrown most of my morning at it, and at this point I'm close to throwing in the towel. I have not even a little bit of js foo -- but I found a nicely commented chunk of code that I'm hoping to use to animate anchor links it is:

$(document).ready(function() {
$('a[href*=#]').bind('click', function(e) {
e.preventDefault(); //prevent the "normal" behaviour which would be a "hard" jump

var target = $(this).attr("href"); //Get the target

var scrollToPosition = $(target).offset().top;

// perform animated scrolling by getting top-position of target-element and set it     as scroll target
$('html, body').stop().animate({ scrollTop: scrollToPosition}, 600, function() {
     location.hash = target;  //attach the hash (#jumptarget) to the pageurl
});

return false;

 });
});

I'm trying to get it to land 30px above the offset().top -- I tried

$('html, body').stop().animate({ scrollTop: scrollToPosition -30}, 600,

Which almost works -- it goes to the right place but then bounces back.

I've also tried

scrollTop: $(target).offset().top - 20 },

I've also tried

scrollTop: $(hash).offset().top + $('#access').outerHeight()

Which doesn't seem to change anything.

It seems like the answer might be here: JQuery page scroll issue with fixed header but I just can't quite seem to get it.

I know this is similar to other questions -- but I've gone through what I could find and I'm illiterate enough that I haven't been able to copy/paste in anything that fixes the issue.

I'd be incredibly grateful for a solution.

Many thanks,

Martin

PS

This other chunk of code I found does work but it's stripping the hashtag out, which makes it mostly useless.

$(function(){
$('a[href*=#]').click(function() {
if (location.pathname.replace(/^//,'') == this.pathname.replace(/^//,'')
    && location.hostname == this.hostname) {
        var $target = $(this.hash);
        $target = $target.length && $target || $('[name=' + this.hash.slice(1) +']');
        if ($target.length) {
            var targetOffset = $target.offset().top;
            $('html,body').animate({scrollTop: targetOffset - 30}, 1000);
            return false;
        }
    }
  });
});
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

EDITED: You just need to detect the height of the fixed header and subtract that from the scrollToPosition which you were doing correctly. The issue is the window.location.hash = "" + target; jumps the page to top of the element with that id. So if you animate there like you were doing and then change to that hash it will "bounce back" like you described. Here is the first way we can combat this:

// Get the height of the header
var headerHeight = $("div#header").height();

// Attach the click event
$('a[href*=#]').bind("click", function(e) {
    e.preventDefault();

    var target = $(this).attr("href"); //Get the target
    var scrollToPosition = $(target).offset().top - headerHeight;

    $('html').animate({ 'scrollTop': scrollToPosition }, 600, function(){
        window.location.hash = "" + target;
        // This hash change will jump the page to the top of the div with the same id
        // so we need to force the page to back to the end of the animation
        $('html').animate({ 'scrollTop': scrollToPosition }, 0);
    });

    $('body').append("called");
});

Here's a new jsfiddle for this first method: http://jsfiddle.net/yjcRv/1/

FURTHER EDIT: An even better way to control hash change events is to use a plugin like jQuery Address. With this you can utilise your hashchange events much more. Here's an example usage:

// Get the height of the header
var headerHeight = $("div#header").height();

$.address.change(function(evt){
    var target = "#" + evt["pathNames"][0]; //Get the target from the event data

    // If there's been some content requested go to it…else go to the top
    if(evt["pathNames"][0]){
        var scrollToPosition = $(target).offset().top - headerHeight;
        $('html').animate({ 'scrollTop': scrollToPosition }, 600);
    }else{
        $('html').animate({ 'scrollTop': '0' }, 600);
    }

    return false;
});

// Attach the click event
$('a').bind("click", function(e) {
    // Change the location
    $.address.value($(this).attr("href"));

    return false;
});

Live example here: http://www.vdotgood.com/stack/user3444.html

NOTE: You don't need to add the hash to your links href attribute now. Here's a link that you could target with a jQuery selector:

<!-- This is correct -->
<a href="/target" class="myclass">Target</a>

<!-- These are incorrect -->
<a href="/#/target" class="myclass">Target</a>

<a href="#/target" class="myclass">Target</a>

To target this link you'd use a selector like:

$("a.myclass").click(function(){
    $.address.value($(this).attr("href"));
    return false;
});

jQuery Address does in fact look for links that have the following attribute:

<a href="/target" rel="address:/target">Target</a>

The rel attribute here contains address: followed by a relative url defined by you in this case /target. If you use this, jQuery Address will detect the link and fire the hash change event automatically.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...