Câu hỏi Thay đổi mục menu đang hoạt động trên trang cuộn?


Một ví dụ điển hình về tính năng này sẽ được thấy ở đây: http://www.maddim.com/demos/spark-r6/

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


76
2018-04-02 16:08


gốc




Các câu trả lời:


Nó được thực hiện bởi liên kết với sự kiện cuộn của thù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 ở trên trong hành động tại jsFiddle bao gồm cả hoạt ảnh cuộn.


170
2018-04-02 16:23



Nếu trình đơn của bạn có kết hợp các ID trên trang và các trang thông thường, trước tiên hãy đặt các liên kết ID trên trang, sau đó thay đổi menuItems = topMenu.find("a"), đến menuItems = topMenu.find("a").slice(0,4),, thay thế 4 với [liên kết trên trang của bạn - 1]. - spsaucier
Tôi thực sự sử dụng menuItems = topMenu.find ('a [href ^ = "#"]'), do đó chỉ trả về các liên kết anchor. Làm việc như một say mê. - Julian K
Fiddle bị hỏng. Bạn có thể sửa nó không? Cám ơn - m1crdy
@ m1crdy Cảm ơn những người đứng đầu. Nó đã được sửa. Có vẻ như một cái gì đó trong jQuery cạnh đã phá vỡ nó. Hoạt động tốt với 2.1.0 :) - mekwall
@JoelAzevedo Có vẻ Sizzle đã thay đổi. Đã cập nhật câu trả lời và trường hợp thử nghiệm để làm việc với jQuery 2.2. - mekwall


Chỉ cần kiểm tra mã của tôi và Sniper 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");
            }
        });
    }

bản trình diễn trực tiếp

$(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);
        });
    });
});

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");
        }
    });
}
body, html {
    margin: 0;
    padding: 0;
    height: 100%;
    width: 100%;
}
.menu {
    width: 100%;
    height: 75px;
    background-color: rgba(0, 0, 0, 1);
    position: fixed;
    background-color:rgba(4, 180, 49, 0.6);
    -webkit-transition: all 0.4s ease;
    -moz-transition: all 0.4s ease;
    -o-transition: all 0.4s ease;
    transition: all 0.4s ease;
}
.light-menu {
    width: 100%;
    height: 75px;
    background-color: rgba(255, 255, 255, 1);
    position: fixed;
    background-color:rgba(4, 180, 49, 0.6);
    -webkit-transition: all 0.4s ease;
    -moz-transition: all 0.4s ease;
    -o-transition: all 0.4s ease;
    transition: all 0.4s ease;
}
#menu-center {
    width: 980px;
    height: 75px;
    margin: 0 auto;
}
#menu-center ul {
    margin: 0 0 0 0;
}
#menu-center ul li a{
		padding: 32px 40px;
}
#menu-center ul li {
    list-style: none;
    margin: 0 0 0 -4px;
    display: inline;

}
.active, #menu-center ul li a:hover  {
    font-family:'Droid Sans', serif;
    font-size: 14px;
    color: #fff;
    text-decoration: none;
    line-height: 50px;
	background-color: rgba(0, 0, 0, 0.12);
	padding: 32px 40px;

}
a {
    font-family:'Droid Sans', serif;
    font-size: 14px;
    color: black;
    text-decoration: none;
    line-height: 72px;
}
#home {
    background-color: #286090;
    height: 100vh;
    width: 100%;
    overflow: hidden;
}
#portfolio {
    background: gray; 
    height: 100vh;
    width: 100%;
}
#about {
    background-color: blue;
    height: 100vh;
    width: 100%;
}
#contact {
    background-color: rgb(154, 45, 45);
    height: 100vh;
    width: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!--	<div class="container">	--->
			<div class="m1 menu">
			<div id="menu-center">
				<ul>
					<li><a class="active" href="#home">Home</a>

					</li>
					<li><a href="#portfolio">Portfolio</a>

					</li>
					<li><a href="#about">About</a>

					</li>
					<li><a href="#contact">Contact</a>

					</li>
				</ul>
			</div>
			</div>
			<div id="home"></div>
			<div id="portfolio"></div>
			<div id="about"></div>
			<div id="contact"></div>


8
2017-07-14 16:06





Chỉ để bổ sung cho câu trả lời của @Marcus Ekwall. Làm như thế này sẽ chỉ nhận được các liên kết anchor. Và bạn sẽ không gặp vấn đề gì nếu bạn có kết hợp các liên kết anchor và các 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ó trong hành động trên jsfiddle


2
2017-10-20 13:35



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 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 hoạt động. Bất kỳ con trỏ được đánh giá cao. - Dickey Singh
Điều nà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 được 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ũng được giải thích rõ ràng ở đây: w3schools.com/css/css_attribute_selectors.asp - Jacques