Ubah Item Menu Aktif di Page Scroll?

95

Saat Anda menggulir ke bawah halaman, item menu yang aktif berubah. Bagaimana ini dilakukan?

Joe Bobby
sumber

Jawaban:

206

Ini dilakukan dengan mengikat ke acara gulir wadah (biasanya jendela).

Contoh cepat:

// 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");
});​

Lihat di atas beraksi di jsFiddle termasuk animasi scroll.

mekwall.dll
sumber
2
Jika menu Anda memiliki campuran ID di halaman dan halaman biasa, tempatkan link ID di halaman terlebih dahulu, lalu ubah menuItems = topMenu.find("a"),ke menuItems = topMenu.find("a").slice(0,4),, ganti 4dengan [link di halaman Anda - 1].
Stephen Saucier
5
Saya sebenarnya menggunakan menuItems = topMenu.find ('a [href ^ = "#"]'), sehingga hanya mengembalikan tautan jangkar. Bekerja seperti pesona.
Julian K
1
Biolanya rusak. Bisakah Anda memperbaikinya? Thx
m1crdy
1
@ m1crdy Terima kasih atas perhatiannya. Sudah diperbaiki. Sepertinya sesuatu di tepi jQuery memecahkannya. Bekerja dengan baik dengan 2.1.0 :)
mekwall
1
@ JoelAzevedo Sepertinya Sizzle telah berubah. Memperbarui jawaban dan kasus uji untuk bekerja dengan jQuery 2.2.
mekwall
16

Cukup periksa Kode dan Penembak Jitu saya dan tautan demo:

    // Basice Code keep it 
    $(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
            }, 500, 'swing', function () {
                window.location.hash = target;
                $(document).on("scroll", onScroll);
            });
        });
    });

// Use Your Class or ID For Selection 

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

demo langsung

MD Ashik
sumber
3

Sekadar melengkapi jawaban @Marcus Ekwall. Melakukan seperti ini hanya akan mendapatkan tautan jangkar. Dan Anda tidak akan mengalami masalah jika Anda memiliki campuran tautan jangkar dan tautan biasa.

jQuery(document).ready(function(jQuery) {            
            var topMenu = jQuery("#top-menu"),
                offset = 40,
                topMenuHeight = topMenu.outerHeight()+offset,
                // All list items
                menuItems =  topMenu.find('a[href*="#"]'),
                // Anchors corresponding to menu items
                scrollItems = menuItems.map(function(){
                  var href = jQuery(this).attr("href"),
                  id = href.substring(href.indexOf('#')),
                  item = jQuery(id);
                  //console.log(item)
                  if (item.length) { return item; }
                });

            // so we can get a fancy scroll animation
            menuItems.click(function(e){
              var href = jQuery(this).attr("href"),
                id = href.substring(href.indexOf('#'));
                  offsetTop = href === "#" ? 0 : jQuery(id).offset().top-topMenuHeight+1;
              jQuery('html, body').stop().animate({ 
                  scrollTop: offsetTop
              }, 300);
              e.preventDefault();
            });

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

               // Get id of current scroll item
               var cur = scrollItems.map(function(){
                 if (jQuery(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 : "";               

               menuItems.parent().removeClass("active");
               if(id){
                    menuItems.parent().end().filter("[href*='#"+id+"']").parent().addClass("active");
               }

            })
        })

Pada dasarnya saya diganti

menuItems = topMenu.find("a"),

oleh

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

Untuk mencocokkan semua tautan dengan jangkar di suatu tempat, dan mengubah semua yang diperlukan untuk membuatnya bekerja dengan ini

Lihat aksinya di jsfiddle

Pablo SG Pacheco
sumber
Bagaimana cara saya memperluas ini untuk menu vertikal khususnya bila menu lebih besar dari halaman? pyze.com/product/docs/index.html Saat pengguna menggulir konten di sebelah kanan, saya ingin mengaktifkan menu yang sesuai di kiri dan menggulir menu jika diperlukan untuk menampilkan menu aktif. Setiap petunjuk dihargai.
Dickey Singh
Ini sangat tuhan, terima kasih. Namun, saya akan mengubah pemilih atribut dari * = menjadi ^ =. Jika Anda menggunakan * = maka Anda juga akan menangkap hal-hal seperti google.com/#something meskipun ini adalah tautan eksternal. Atribut pemilih baik dijelaskan di sini: w3schools.com/css/css_attribute_selectors.asp
Jacques
0

Jika Anda ingin jawaban yang diterima berfungsi di JQuery 3, ubah kode seperti ini:

var scrollItems = menuItems.map(function () {
    var id = $(this).attr("href");
    try {
        var item = $(id);
      if (item.length) {
        return item;
      }
    } catch {}
  });

Saya juga menambahkan coba-tangkap untuk mencegah javascript mogok jika tidak ada elemen oleh id itu. Jangan ragu untuk meningkatkannya lebih banyak lagi;)

Tim Gerhard
sumber