简体   繁体   中英

jQuery page scroll not changing navbar href to active class

I have a one-page website. When I scroll down I want my (fixed) navbar links to change the status to active when reaching the position of that specific div.

I used jQuery but it doesn't work. Here is my code:

// SMOOTH SCROLLING PAGES

$(document).ready(function () {
$(document).on("scroll", onScroll);

//smoothscroll
$('a[href^="#"]').on('click', function (e) {
    e.preventDefault();
    $(document).off("scroll");

    $('a').each(function () {
        $(this).removeClass('active');
    })
    $(this).addClass('active');

    var target = this.hash,
        menu = target;
    $target = $(target);
    $('html, body').stop().animate({
        'scrollTop': $target.offset().top+2
    }, 800, 'swing', function () {
        window.location.hash = target;
        $(document).on("scroll", onScroll);
    });
  });
});

function onScroll(event){
var scrollPos = $(document).scrollTop();
$('main-navigation a').each(function () {
    var currLink = $(this);
    var refElement = $(currLink.attr("href"));
    if (refElement.position().top <= scrollPos && refElement.position().top + refElement.height() > scrollPos) {
        $('main-navigation ul li a').removeClass("active");
        currLink.addClass("active");
    }
    else{
        currLink.removeClass("active");
    }
  });
};

Here is my HTML:

<nav id="main-navigation">
  <ul>
    <li class="active"><a href="#site-main">Home</a></li>
    <li><a href="#a">A</a></li>
    <li><a href="#b">B</a></li>
    <li><a href="#c">C</a></li>
    <li><a href="#d">D</a></li>
  </ul>
</nav>
<div id="a">DIV Alpha</div>
<div id="b">DIV Bravo</div>
<div id="c">DIV Charlie</div>
<div id="d">DIV Delta</div>

The smooth scrolling works perfectly, but when I scrolling back up from div #d the navbar li active state doesn't change.

Here, i prepare fiddle for you, i hope it what you looking for - http://jsfiddle.net/skyr9999/dpuvcj5w

<div class="content">
    <div id="site-main">DIV Home</div>
    <div id="a">DIV Alpha</div>
    <div id="b">DIV Bravo</div>
    <div id="c">DIV Charlie</div>
    <div id="d">DIV Delta</div>
</div>

<nav id="main-navigation">
    <ul>
        <li><a class="menuitem" href="#site-main">Home</a></li>
        <li><a class="menuitem" href="#a">A</a></li>
        <li><a class="menuitem" href="#b">B</a></li>
        <li><a class="menuitem" href="#c">C</a></li>
        <li><a class="menuitem" href="#d">D</a></li>
    </ul>
</nav>

js

$(document).ready(function () {

    $('a[href^="#site-main"]').addClass('active');

//smoothscroll
    $('.menuitem').on('click', function (e) {
        e.preventDefault();
        //  $(document).off("scroll");
        var athis = this;
        var target = this.hash,
                menu = target;
        $target = $(target);
        $('html, body').stop().animate({
            'scrollTop': $target.offset().top + 2
        }, 800, 'swing', function () {
            window.location.hash = target;
            $('.menuitem').removeClass('active');
            $(athis).addClass('active');

        });    
    });    

    $(window).scroll(function (event) {
        var scrollPos = $(document).scrollTop();
        if (scrollPos === 0)
        {
            $('a[href^="#site-main"]').addClass('active');
            return;
        }    
        $('.menuitem').each(function () {
            var currLink = $(this);
            var refElement = $(currLink.attr("href"));
            if (refElement.position().top <= scrollPos && refElement.position().top + refElement.height() > scrollPos) {
                $('.menuitem').removeClass("active");
                currLink.addClass("active");
            } else {
                currLink.removeClass("active");
            }
        });    
    })    
});

Because you did not include any css, i improvise a little, but it seems works just fine.

css

#a,#b,#c,#d,#site-main { height: 400px;}
#main-navigation {
    position: fixed;
    top: 0px;
    right:10px;        
}

#main-navigation ul li {
  display: inline;
}

.active {
  background: #f00;
}

Update 1 I update code to match fiddle now it change menu item selection when you scrool to item

You have to loop through with the list items instead and correct the id selector with a # notation:

$('#main-navigation li').each(function () { //<---correct id selector
    var currLink = $(this);
    var refElement = $(currLink.find('a').attr("href")); //<---find the anchor here
    if (refElement.position().top <= scrollPos && refElement.position().top + refElement.height() > scrollPos) {
        $('#main-navigation ul li').removeClass("active"); //<---and here
        currLink.addClass("active");
    }
    else{
        currLink.removeClass("active");
    }
});

you can use this cool tiny plugin to achieve this https://github.com/davist11/jQuery-One-Page-Nav

it will add current class when you are in a specific div or section Hope this help :)

replace

$('a').each(function () { $(this).removeClass('active'); }) $(this).addClass('active');

with

$('a').each(function () {
    $(this).parent().removeClass('active');
})
$(this).parent().addClass('active');

complete code:

$('a[href^="#"]').on('click', function (e) {
e.preventDefault();
$(document).off("scroll");

$('a').each(function () {
    $(this).parent().removeClass('active');
})
$(this).parent().addClass('active');

var target = this.hash,
    menu = target;
$target = $(target);
$('html, body').stop().animate({
    'scrollTop': $target.offset().top+2
}, 800, 'swing', function () {
    window.location.hash = target;
});

});

No need of onScroll function

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM