페이지 스크롤에서 활성 메뉴 항목을 변경 하시겠습니까?


95

페이지를 아래로 스크롤하면 활성 메뉴 항목이 변경됩니다. 어떻게하나요?

답변:


206

컨테이너 (일반적으로 창) 의 스크롤 이벤트바인딩하여 수행됩니다 .

빠른 예 :

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

스크롤 애니메이션을 포함하여 jsFiddle에서의 작업을 참조하십시오 .


2
메뉴에 온 페이지 ID와 일반 페이지가 혼합되어있는 경우 먼저 온 페이지 ID 링크를 배치 한 다음 [페이지 내 링크-1]로 대체 하여 로 변경 menuItems = topMenu.find("a"),합니다 . menuItems = topMenu.find("a").slice(0,4),4
Stephen Saucier 2013

5
실제로 menuItems = topMenu.find ( 'a [href ^ = "#"]')를 사용하여 앵커 링크 만 반환했습니다. 매력처럼 작동합니다.
Julian K

1
바이올린이 고장났습니다. 고칠 수 있습니까? Thx
m1crdy 2014 년

1
@ m1crdy 머리를 올려 주셔서 감사합니다. 수정되었습니다. jQuery edge의 무언가가 망가진 것 같습니다. 2.1.0 :)와 함께 잘 작동
mekwall

1
@JoelAzevedo Sizzle이 변경된 것 같습니다. jQuery 2.2에서 작동하도록 답변과 테스트 케이스를 업데이트했습니다.
mekwall

16

내 코드와 스나이퍼 및 데모 링크를 확인하십시오.

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

데모 라이브


3

@Marcus Ekwall의 답변을 보완하기 위해. 이렇게하면 앵커 링크 만 얻게됩니다. 그리고 앵커 링크와 일반 링크가 혼합되어 있으면 문제가 발생하지 않습니다.

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

            })
        })

기본적으로 나는 대체

menuItems = topMenu.find("a"),

으로

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

모든 링크를 어딘가에 앵커와 일치시키고 이것으로 작동하는 데 필요한 모든 것을 변경했습니다.

jsfiddle 에서 실제로 확인하십시오.


특히 메뉴가 페이지보다 클 때 수직 메뉴에 대해 이것을 어떻게 확장합니까? pyze.com/product/docs/index.html 사용자가 오른쪽의 콘텐츠를 스크롤 할 때 왼쪽에서 적절한 메뉴를 활성화하고 필요한 경우 메뉴를 스크롤하여 활성 메뉴를 표시하고 싶습니다. 모든 조언을 부탁드립니다.
Dickey Singh

이건 정말 신이에요, 감사합니다. 그러나 속성 선택기를 * =에서 ^ =로 변경합니다. * =를 사용 하면 외부 링크 임에도 불구하고 google.com/#something 과 같은 것도 잡을 수 있습니다 . 속성 선택이 아니라 여기에 설명되어 있습니다 w3schools.com/css/css_attribute_selectors.asp
자크

0

허용 된 답변이 JQuery 3에서 작동하도록하려면 다음과 같이 코드를 변경하십시오.

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

또한 해당 ID의 요소가없는 경우 자바 스크립트가 충돌하지 않도록 try-catch를 추가했습니다. 더 개선해 주시기 바랍니다;)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.