简体   繁体   中英

On page scroll add active class to matching <a href>hash in fixed menu

This one has been taking up a bit of my time to figure out so I'm appealing for someone to brighten my day.

This popular piece of code, works great if your menu links only contain #hashlocation - it updates your menu item with the active class when you down at that part of the page.

// Cache selectors
var topMenu = $("#top-menu"),
    topMenuHeight = topMenu.outerHeight()+15,
    // All list items
    menuItems = topMenu.find("a"),
    // Anchors corresponding to menu items
    scrollItems = menuItems.map(function(){
      var item = $($(this).attr("href"));
      if (item.length) { return item; }
    });

// Bind to scroll
$(window).scroll(function(){
   // Get container scroll position
   var fromTop = $(this).scrollTop()+topMenuHeight;

   // Get id of current scroll item
   var cur = scrollItems.map(function(){
     if ($(this).offset().top < fromTop)
       return this;
   });
   // Get the id of the current element
   cur = cur[cur.length-1];
   var id = cur && cur.length ? cur[0].id : "";
   // Set/remove active class
   menuItems
     .parent().removeClass("active")
     .end().filter("[href=#"+id+"]").parent().addClass("active");
});​

The issue for me , is that it obviously doesn't work if my menu contains other pages that are not hash tags, and in particular with the ones that do have hashtags, they are preceded with the full URL .

I need this code to be adjusted so that it does not throw a "syntax error, unrecognized expression", and also accept the fact that the menu may contain other links pointing elsewhere.

Here is a fiddle http://jsfiddle.net/stevenmunro/ytbhrz1g/2/

if you would remove the full URL before the hash from "Foo" it will work.

I have tried

menuItems = topMenu.find('a[href*=#]'),

and also inside scrollItems = menuItems.map

var item = $($(this).attr("href").split("#"));
item = $("#" + item[1]);

References

Change Active Menu Item on Page Scroll?

Appreciate your help.

Thanks to James Hay for putting me on the right track. The suggestion was very similar to what I had already tried, however it's now a one-liner and works well.

I also changed;

menuItems = topMenu.find("a"),

to

menuItems = topMenu.find('a[href*=#]'),

and changed;

menuItems
 .parent().removeClass("active")
 .end().filter("[href=#"+id+"]").parent().addClass("active");

to

menuItems
 .parent().removeClass("active")
 .end().filter("[href$=" + id + "]").parent().addClass("active");

As long as the items in the menu and in order as they are too down the page, this will work. If the menu items are scrambled up, it will not change as expected. Perhaps that is something else we could figure out too, but the question is answered so thank you.

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