'On scroll underline a menu item based on the id of the portion where the final user is
Here's my problem and my code:
var lastId,
topMenu = $("#menu-main-menu"),
topMenuHeight = headerheight+1,
menuItems = topMenu.find("a"),
scrollItems = menuItems.map(function() {
if($(this).parent().hasClass('external')) {
return;
}
var item = $($(this).attr("href"));
if (item.length) {
return item;
}
});
$(window).on("scroll", function() {
const fromTop = $(this).scrollTop()+topMenuHeight;
let cur = scrollItems.map(function() {
if ($(this).offset().top < fromTop) {
return this;
}
});
cur = cur[cur.length-1];
let id = cur && cur.length ? cur[0].id : "";
if (lastId !== id) {
lastId = id;
menuItems
.parent().removeClass("underline")
.end().filter("[href='#"+id+"']").parent().addClass("underline");
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="navbarNav" class="menu-main-menu-container">
<ul id="menu-main-menu" class="menu"><li id="menu-item-17" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-17"><a href="#test2">Veelgestelde vragen</a></li>
<li id="menu-item-18" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-18"><a href="#test1">Test1</a></li>
<li id="menu-item-19" class="active menu-item menu-item-type-custom menu-item-object-custom menu-item-19"><a href="#test3">Test2</a></li>
<li id="menu-item-20" class="external menu-item menu-item-type-custom menu-item-object-custom menu-item-20"><a href="http://www.confiban.com">Test3</a></li>
</ul>
</div>
<div class="lazyblock-section" id="section-extra-Z1YeUxc">
<div id="test1" class="background-color" style="background-size: cover;background-color: #fff; ">
</div>
</div>
</body>
</html>
Essentially, I create a menu and, based on another script here on stackoverflow, I created a jquery script to underline the menu item, based on the portion of the screen where the user will scroll.
It works but with a caveat. I will only work if the list is order, for example if the menu will be:
<li id="menu-item-18"><a href="#test1">Test1</a></li>
<li id="menu-item-19"><a href="#test2">Test2</a></li>
<div class="lazyblock-section">
<div id="test1">
</div>
</div>
<div class="lazyblock-section">
<div id="test2">
</div>
</div>
but if the markup will be:
<li id="menu-item-18"><a href="#test1">Test1</a></li>
<li id="menu-item-19"><a href="#test2">Test2</a></li>
<div class="lazyblock-section">
<div id="test2">
</div>
</div>
<div class="lazyblock-section">
<div id="test1">
</div>
</div>
The script won't work.
Now the client will have the freedom to order every element of the menu, and I tried to console.log every single variable here finding out that the script is working fun, but not being able to properly debug:
Apparently the only variable that is not clear for me is cur:
cur = cur[cur.length-1];
let id = cur && cur.length ? cur[0].id : "";
I tried to ged rid of the value [cur.length-1] but it is not working as it should.
Any suggestion?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
