Thay đổi Mục Menu Hoạt động trên Cuộn trang?


95

Khi bạn cuộn xuống trang, mục menu hoạt động sẽ thay đổi. Làm thế nào là điều này được thực hiện?

Câu trả lời:


205

Nó được thực hiện bằng cách liên kết với sự kiện cuộn của vùng chứa (thường là cửa sổ).

Ví dụ nhanh:

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

Xem hành động ở trên tại jsFiddle bao gồm cả hoạt ảnh cuộn.


2
Nếu menu của bạn có sự kết hợp giữa ID trên trang và các trang thông thường, hãy đặt các liên kết ID trên trang trước, sau đó thay đổi menuItems = topMenu.find("a"),thành menuItems = topMenu.find("a").slice(0,4),, thay thế 4bằng [liên kết trên trang của bạn - 1].
Stephen Saucier

5
Tôi thực sự đã sử dụng menuItems = topMenu.find ('a [href ^ = "#"]'), do đó chỉ trả về các liên kết cố định. Hoạt động như một sự quyến rũ.
Julian K

1
Cỗ máy bị hỏng. Bạn có thể sửa chữa nó? Thx
m1crdy

1
@ m1crdy Cảm ơn bạn đã quan tâm. Nó đã được sửa. Có vẻ như thứ gì đó trong jQuery edge đã phá vỡ nó. Hoạt động tốt với 2.1.0 :)
mekwall

1
@JoelAzevedo Có vẻ Sizzle đã thay đổi. Đã cập nhật câu trả lời và trường hợp kiểm tra để hoạt động với jQuery 2.2.
mekwall

16

Chỉ cần kiểm tra Mã và Bắn tỉa của tôi và liên kết 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 trực tiếp


3

Chỉ để bổ sung cho câu trả lời của @Marcus Ekwall. Làm như vậy sẽ chỉ nhận được liên kết neo. Và bạn sẽ không gặp vấn đề nếu bạn có sự kết hợp giữa liên kết neo và liên kết thông thường.

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

            })
        })

Về cơ bản tôi đã thay thế

menuItems = topMenu.find("a"),

bởi

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

Để khớp tất cả các liên kết với neo ở đâu đó và thay đổi tất cả những gì cần thiết để làm cho nó hoạt động với điều này

Xem nó hoạt động trên jsfiddle


Làm cách nào để mở rộng điều này cho menu dọc, đặc biệt khi menu lớn hơn trang? pyze.com/product/docs/index.html Khi người dùng cuộn lên nội dung ở bên phải, tôi muốn kích hoạt menu thích hợp ở bên trái và cuộn menu nếu cần để hiển thị menu đang hoạt động. Bất kỳ con trỏ nào được đánh giá cao.
Dickey Singh

Đây là rất thần, cảm ơn bạn. Tuy nhiên, tôi sẽ thay đổi bộ chọn thuộc tính từ * = thành ^ =. Nếu bạn sử dụng * = thì bạn cũng sẽ bắt gặp những thứ như google.com/#something mặc dù đây là một liên kết bên ngoài. Bộ chọn thuộc tính được giải thích rõ ràng tại đây: w3schools.com/css/css_attribute_selectors.asp
Jacques

0

Nếu bạn muốn câu trả lời được chấp nhận hoạt động trong JQuery 3, hãy thay đổi mã như sau:

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

Tôi cũng đã thêm một try-catch để ngăn javascript bị lỗi nếu không có phần tử nào theo id đó. Hãy cải thiện nó nhiều hơn nữa;)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.