Скользащее меню и позиция по умолчанию

253
26 ноября 2016, 18:52

В меню есть 2 скрипта.

Один скрипт при нажатии на кнопку меню скролит окно браузера к соответствующему блоку, а так же присваивает класс active выбранной кнопке меню li.

Второй скрипт плавно подчеркивает пункты меню при наведении зеленой линией. При загрузке страницы подчеркивается кнопка li которой задан класс active а уже от нее подчеркивающая линия перемещается при наведении.

Проблема в том, что выбранный пункт меню, которому задан класс active при загрузке страницы, он для второго скрипта так и остается подчеркнутым по умолчанию даже если класс active будет уже на другой кнопке.

Возможно ли как-то сделать так, чтобы при скороле нижняя скользящая линия меняла свою позицию по умолчанию так же как и красная полоса сверху в примере. То есть, чтобы начальная координата зеленой линии всегда была на кнопке active как это делает красная линия, а не только при первой загрузке

Или подскажите альтернативу скользящей линии, которая бы работала таким образом.

// первый скрипт 
// Cache selectors 
var lastId, 
    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 click handler to menu items 
// so we can get a fancy scroll animation 
menuItems.click(function(e){ 
  var href = $(this).attr("href"), 
      offsetTop = href === "#" ? 0 : $(href).offset().top-topMenuHeight+1; 
  $('html, body').stop().animate({  
      scrollTop: offsetTop 
  }, 300); 
  e.preventDefault(); 
}); 
 
// 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 : ""; 
    
   if (lastId !== id) { 
       lastId = id; 
       // Set/remove active class 
       menuItems 
         .parent().removeClass("active") 
         .end().filter("[href='#"+id+"']").parent().addClass("active"); 
   }                    
}); 
 
// второй скрипт 
 
$(document).ready(function(){ 
  
    var nav_wrap = $(".sliding-menu"), 
        elem_width, 
        elem_left_offset, 
        elem_parent, 
        slider_line; 
      
    $(document).ready(function(){ 
  
        nav_wrap.each(function(){ 
            $(this).append('<li class="sliding-line"></li>'); 
  
            var start_elem_width = 0; 
            var start_elem_offset = 0; 
            var active_elem = $(this).find(".active"); 
  
            if(active_elem.length){ 
                start_elem_width = active_elem.outerWidth(); 
                start_elem_offset = active_elem.position().left; 
            } 
  
            $(this).find(".sliding-line").css({ 
                "width": start_elem_width + "px", 
                "left": start_elem_offset + "px" 
            }) 
            .data("width", start_elem_width) 
            .data("left", start_elem_offset); 
        }); 
  
    }); 
  
    nav_wrap.find("li a").hover(function(){ 
  
        elem_parent = $(this).parent(); 
        elem_width = elem_parent.outerWidth(); 
        elem_left_offset = $(this).position().left; 
        slider_line = elem_parent.siblings(".sliding-line"); 
        slider_line.stop().animate({ 
            "width": elem_width + "px", 
            "left": elem_left_offset + "px" 
        }); 
  
    }, function(){ 
  
        slider_line.stop().animate({ 
            "width": slider_line.data("width") + "px", 
            "left": slider_line.data("left") + "px" 
        }); 
            
    }); 
  
});
body { 
    height: 6000px; 
    font-family: Helvetica, Arial; 
  margin-top: 500px; 
} 
 
#top-menu { 
    position: fixed; 
    z-index: 1; 
    background: white; 
    left: 0; 
    right: 0; 
    top: 0; 
} 
 
#top-menu li { 
    float: left; 
} 
 
#top-menu a { 
    display: block; 
    padding: 5px 25px 7px 25px; 
    width: 4em; 
    text-align: center; 
    -webkit-transition: .5s all ease-out; 
    -moz-transition: .5s all ease-out; 
    transition: .5s all ease-out; 
    border-top: 3px solid white; 
    color: #aaa; 
    text-decoration: none; 
} 
 
#top-menu a:hover { 
    color: #000; 
} 
 
#top-menu .active { 
border-top: 1px solid red;   
} 
 
 
div { 
  height: 1000px; 
  padding-top: 40px; 
} 
 
 
 
.sliding-line { 
    height: 2px; /* Задаем высоту нашей "скользящей" полоске */ 
    background: #6da047; /* Задаем цвет для "скользящей" полоски */ 
    position: absolute; /* Позиционируем полоску абсолютным образом */ 
    bottom: -2px; /* Смещаем ее вниз на 2 пикселя. Здесь, как правило, задается значение эквивалентное высоте полоски, но только со знаком минус */ 
    left: 0; 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.1/jquery.min.js"></script> 
<ul id="top-menu" class="sliding-menu"> 
  <li class="active"> 
    <a href="#">Top</a> 
  </li> 
  <li> 
    <a href="#foo">Foo</a> 
  </li> 
  <li> 
    <a href="#bar">Bar</a> 
  </li> 
  <li> 
    <a href="#baz">Baz</a> 
  </li> 
</ul> 
 
<div id="foo">Foo</div> 
 
 
<div id="bar">Bar</div> 
 
 
<div id="baz">Baz</div>

Answer 1

Можно сделать например так (изменена вторая функция в hover):

// первый скрипт 
// Cache selectors 
var lastId, 
    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 click handler to menu items 
// so we can get a fancy scroll animation 
menuItems.click(function(e){ 
  var href = $(this).attr("href"), 
      offsetTop = href === "#" ? 0 : $(href).offset().top-topMenuHeight+1; 
  $('html, body').stop().animate({  
      scrollTop: offsetTop 
  }, 300); 
  e.preventDefault(); 
}); 
 
// 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 : ""; 
    
   if (lastId !== id) { 
       lastId = id; 
       // Set/remove active class 
       menuItems 
         .parent().removeClass("active") 
         .end().filter("[href='#"+id+"']").parent().addClass("active"); 
   }                    
}); 
 
// второй скрипт 
 
$(document).ready(function(){ 
  
    var nav_wrap = $(".sliding-menu"), 
        elem_width, 
        elem_left_offset, 
        elem_parent, 
        slider_line; 
      
    $(document).ready(function(){ 
  
        nav_wrap.each(function(){ 
            $(this).append('<li class="sliding-line"></li>'); 
  
            var start_elem_width = 0; 
            var start_elem_offset = 0; 
            var active_elem = $(this).find(".active"); 
  
            if(active_elem.length){ 
                start_elem_width = active_elem.outerWidth(); 
                start_elem_offset = active_elem.position().left; 
            } 
  
            $(this).find(".sliding-line").css({ 
                "width": start_elem_width + "px", 
                "left": start_elem_offset + "px" 
            }) 
            .data("width", start_elem_width) 
            .data("left", start_elem_offset); 
        }); 
  
    }); 
  
    nav_wrap.find("li a").hover(function(){  
        elem_parent = $(this).parent(); 
        elem_width = elem_parent.outerWidth(); 
        elem_left_offset = $(this).position().left; 
        slider_line = elem_parent.siblings(".sliding-line"); 
        slider_line.stop().animate({ 
            "width": elem_width + "px", 
            "left": elem_left_offset + "px" 
        });  
    }, function(){ 
        setTimeout(function(){ 
            var active = $('.active', nav_wrap); 
            slider_line.stop().animate({ 
                "width": active.width() + "px", 
                "left": active.position().left + "px" 
            }); 
        }, 500); 
            
    }); 
  
});
body { 
    height: 6000px; 
    font-family: Helvetica, Arial; 
  margin-top: 500px; 
} 
 
#top-menu { 
    position: fixed; 
    z-index: 1; 
    background: white; 
    left: 0; 
    right: 0; 
    top: 0; 
} 
 
#top-menu li { 
    float: left; 
} 
 
#top-menu a { 
    display: block; 
    padding: 5px 25px 7px 25px; 
    width: 4em; 
    text-align: center; 
    -webkit-transition: .5s all ease-out; 
    -moz-transition: .5s all ease-out; 
    transition: .5s all ease-out; 
    border-top: 3px solid white; 
    color: #aaa; 
    text-decoration: none; 
} 
 
#top-menu a:hover { 
    color: #000; 
} 
 
#top-menu .active { 
border-top: 1px solid red;   
} 
 
 
div { 
  height: 1000px; 
  padding-top: 40px; 
} 
 
 
 
.sliding-line { 
    height: 2px; /* Задаем высоту нашей "скользящей" полоске */ 
    background: #6da047; /* Задаем цвет для "скользящей" полоски */ 
    position: absolute; /* Позиционируем полоску абсолютным образом */ 
    bottom: -2px; /* Смещаем ее вниз на 2 пикселя. Здесь, как правило, задается значение эквивалентное высоте полоски, но только со знаком минус */ 
    left: 0; 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.1/jquery.min.js"></script> 
<ul id="top-menu" class="sliding-menu"> 
  <li class="active"> 
    <a href="#">Top</a> 
  </li> 
  <li> 
    <a href="#foo">Foo</a> 
  </li> 
  <li> 
    <a href="#bar">Bar</a> 
  </li> 
  <li> 
    <a href="#baz">Baz</a> 
  </li> 
</ul> 
 
<div id="foo">Foo</div> 
 
 
<div id="bar">Bar</div> 
 
 
<div id="baz">Baz</div>

Но есть баги, тк .active а вас добавляется не сразу после перехода. Красный бегунок стоит сделать по аналогии с зеленым отдельным элементом.

Answer 2

в конец 1 скрипта, добавлено установка координат возвращения на активный пункт.

// первый скрипт 
// Cache selectors 
var lastId, 
  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 click handler to menu items 
// so we can get a fancy scroll animation 
menuItems.click(function(e) { 
  var href = $(this).attr("href"), 
    offsetTop = href === "#" ? 0 : $(href).offset().top - topMenuHeight + 1; 
  $('html, body').stop().animate({ 
    scrollTop: offsetTop 
  }, 300); 
  e.preventDefault(); 
}); 
 
// 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 : ""; 
 
  if (lastId !== id) { 
    lastId = id; 
    // Set/remove active class 
    var act = menuItems 
      .parent().removeClass("active") 
      .end().filter("[href='#" + id + "']").parent().addClass("active"); 
    act.siblings(".sliding-line") 
      .data({ 
        "width": act.outerWidth(), 
        "left": act.position().left 
      }) 
 
  } 
 
}); 
 
// второй скрипт 
 
$(document).ready(function() { 
 
  var nav_wrap = $(".sliding-menu"), 
    elem_width, 
    elem_left_offset, 
    elem_parent, 
    slider_line; 
 
  $(document).ready(function() { 
 
    nav_wrap.each(function() { 
      $(this).append('<li class="sliding-line"></li>'); 
 
      var start_elem_width = 0; 
      var start_elem_offset = 0; 
      var active_elem = $(this).find(".active"); 
 
      if (active_elem.length) { 
        start_elem_width = active_elem.outerWidth(); 
        start_elem_offset = active_elem.position().left; 
      } 
 
      $(this).find(".sliding-line").css({ 
          "width": start_elem_width + "px", 
          "left": start_elem_offset + "px" 
        }) 
        .data("width", start_elem_width) 
        .data("left", start_elem_offset); 
    }); 
 
  }); 
 
  nav_wrap.find("li a").hover(function() { 
 
    elem_parent = $(this).parent(); 
    elem_width = elem_parent.outerWidth(); 
    elem_left_offset = $(this).position().left; 
    slider_line = elem_parent.siblings(".sliding-line"); 
    slider_line.stop().animate({ 
      "width": elem_width + "px", 
      "left": elem_left_offset + "px" 
    }); 
 
  }, function() { 
 
    slider_line.stop().animate({ 
      "width": slider_line.data("width") + "px", 
      "left": slider_line.data("left") + "px" 
    }); 
 
  }); 
 
});
body { 
  height: 6000px; 
  font-family: Helvetica, Arial; 
  margin-top: 500px; 
} 
#top-menu { 
  position: fixed; 
  z-index: 1; 
  background: white; 
  left: 0; 
  right: 0; 
  top: 0; 
} 
#top-menu li { 
  float: left; 
} 
#top-menu a { 
  display: block; 
  padding: 5px 25px 7px 25px; 
  width: 4em; 
  text-align: center; 
  -webkit-transition: .5s all ease-out; 
  -moz-transition: .5s all ease-out; 
  transition: .5s all ease-out; 
  border-top: 3px solid white; 
  color: #aaa; 
  text-decoration: none; 
} 
#top-menu a:hover { 
  color: #000; 
} 
#top-menu .active { 
  border-top: 1px solid red; 
} 
div { 
  height: 1000px; 
  padding-top: 40px; 
} 
.sliding-line { 
  height: 2px; 
  /* Задаем высоту нашей "скользящей" полоске */ 
  background: #6da047; 
  /* Задаем цвет для "скользящей" полоски */ 
  position: absolute; 
  /* Позиционируем полоску абсолютным образом */ 
  bottom: -2px; 
  /* Смещаем ее вниз на 2 пикселя. Здесь, как правило, задается значение эквивалентное высоте полоски, но только со знаком минус */ 
  left: 0; 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.1/jquery.min.js"></script> 
<ul id="top-menu" class="sliding-menu"> 
  <li class="active"> 
    <a href="#">Top</a> 
  </li> 
  <li> 
    <a href="#foo">Foo</a> 
  </li> 
  <li> 
    <a href="#bar">Bar</a> 
  </li> 
  <li> 
    <a href="#baz">Baz</a> 
  </li> 
</ul> 
 
<div id="foo">Foo</div> 
 
 
<div id="bar">Bar</div> 
 
 
<div id="baz">Baz</div>

READ ALSO
Есть ли способ перевернуть текст на css?

Есть ли способ перевернуть текст на css?

мне кажется что для этого использовать js лишнее

393
Как задать footer в React js Bootsrap?

Как задать footer в React js Bootsrap?

Хочу сделать компонент реакта, который служил бы footer'ом для веб страницыВ документации по react-bootstrap нашел упоминание о футере только в связке...

346
Margin после row Bootstrap

Margin после row Bootstrap

Ребят, не получается сделать margin-top дляrow класса, т

666
Как сделать градиент поверх картинки?

Как сделать градиент поверх картинки?

Должна быть картинка, градиент, и текст поверх всего этогоНикак не получается сделать, пробую разные приемы, ничего не срабатывает

474