Pytanie Zmienić pozycję aktywnego menu na przewijaniu stron?


Dobry przykład tej funkcji można zobaczyć tutaj: http://www.maddim.com/demos/spark-r6/

Podczas przewijania strony zmienia się aktywny element menu. Jak to się robi?


76
2018-04-02 16:08


pochodzenie




Odpowiedzi:


To zrobione przez powiązanie z wydarzeniem przewijania pojemnika (zwykle okno).

Szybki przykład:

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

Zobacz powyższe w akcji na jsFiddle w tym animacja przewijania.


170
2018-04-02 16:23



Jeśli menu zawiera wiele identyfikatorów na stronie i zwykłych stron, najpierw umieść łącza do identyfikatorów na stronie, a następnie zmień menuItems = topMenu.find("a"), do menuItems = topMenu.find("a").slice(0,4),, zastępując 4 z [twoje linki na stronie - 1]. - spsaucier
Właściwie użyłem menuItems = topMenu.find ('a [href ^ = "#"]'), zwracając w ten sposób tylko linki kotwicy. Działa jak marzenie. - Julian K
Skrzypce jest zepsute. Czy możesz to naprawić? Dzięki - m1crdy
@ m1crdy Dzięki za heads up. Zostało to naprawione. Wygląda na to, że coś zepsuło to w krawędź jQuery. Działa dobrze z 2.1.0 :) - mekwall
@JoelAzevedo Wydaje się, że Sizzle się zmieniło. Zaktualizowano odpowiedź i przypadek testowy, aby pracować z jQuery 2.2. - mekwall


Po prostu sprawdź mój kod i link do snajpera i 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");
            }
        });
    }

wersja demonstracyjna na żywo

$(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





Tylko po to, aby uzupełnić odpowiedź @Marcus Ekwall. W ten sposób otrzymasz tylko linki kotwiczne. I nie będziesz mieć problemów, jeśli masz mieszankę łączy kotwicznych i regularnych.

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

            })
        })

Zasadniczo ja wymieniłem

menuItems = topMenu.find("a"),

przez

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

Aby dopasować wszystkie linki z zakotwiczeniem gdzieś i zmienić wszystko, co było konieczne, aby działało z tym

Zobacz to w akcji na jsfiddle


2
2017-10-20 13:35



Jak mogę to rozszerzyć dla menu wertykalnego, szczególnie gdy menu jest większe niż strona? pyze.com/product/docs/index.html Gdy użytkownik przewija zawartość po prawej stronie, chciałbym aktywować odpowiednie menu po lewej stronie i przewinąć menu, jeśli jest to konieczne, aby pokazać aktywne menu. Wszelkie wskazówki są mile widziane. - Dickey Singh
To bardzo bóg, dziękuję. Zmieniłbym jednak selektor atrybutów z * = na ^ =. Jeśli użyjesz * =, wtedy złapiesz też takie rzeczy google.com/#something mimo że jest to link zewnętrzny. Selektor atrybutów jest dobrze wyjaśniony tutaj: w3schools.com/css/css_attribute_selectors.asp - Jacques