简体   繁体   中英

Confused about highlighting active menu item on scroll (Vanilla JS)

I found this function which highlights the active menu anchors when you scroll to sections that have the same id. I understand how most of the code works, but I don't get how the window onscroll event knows how to update the right anchor tag with the .active class.

All the JS:

  var section = document.querySelectorAll(".section"); var sections = {}; var i = 0; Array.prototype.forEach.call(section, function(e) { sections[e.id] = e.offsetTop; }); window.onscroll = function() { var scrollPosition = document.documentElement.scrollTop || document.body.scrollTop; for (i in sections) { if (sections[i] <= scrollPosition) { document.querySelector('.active').setAttribute('class', ' '); document.querySelector('a[href*=' + i + ']').setAttribute('class', 'active'); } } }; 

From this Pen: https://codepen.io/zchee/pen/ogzvZZ

This part confuses me:

document.querySelector('a[href*=' + i + ']').setAttribute('class', 'active');

I get that setAttribute adds a class of active to the anchor tag — but how does querySelector find the right anchor to update when you scroll?

I tried logging the index variable [i] from the (for in array loop) to get the id of the current section (onscroll) but it returns the current scroll position (as a number).

This is why I don't get why the inserted 'i' variable here: ('a[href*=' + i + ']') represents the corresponding section id in the onscroll event.

I guess it doesn't help that I don't really understand how this forEach function operates:

Array.prototype.forEach.call(section, function(e) {
sections[e.id] = e.offsetTop;
});

I get that it loops through all sections and pushes the sections[e.id] to the empty object sections = {} which is used later in the onscroll event — but that's where my understanding stops. :-/

I'm sorry I don't know how to phrase this question better. I've spent hours trying to wrap my head around it. I can't find any topic examples that are similar to this, but I want to understand how it works before I use it anywhere.

Would greatly appreciate some feedback! :-)

According to documentation from W3 schools, .querySelector gets the first element in the document with class equalling the one being searched for.

a[href*=#] means the querySelector is looking for all elements containing a # , and in your case 'a[href*=' + i + ']' is further specifying elements that has the current href of i .

So when you piece everything together, the code

for (i in sections) {
  if (sections[i] <= scrollPosition) {
    document.querySelector('.active').setAttribute('class', ' ');
    document.querySelector('a[href*=' + i + ']').setAttribute('class', 'active');
  }
}

looks for the element with an href equalling the current 'i' section, and sets the attribute class to active for that element.

Hope it helps!

EDIT

Whenever the window is scrolled, the following happens:

  1. 1) A variable is set called scrollPosition , which is set equal to the documentElement's "highest" point (or scrollTop) OR the document body's "highest" point (or scrollTop)
  2. Then, for i in all sections: if the section is less than or equal to the scrollPostition, it changes the previously active class to null and sets the current section's class to active.

It then repeats for each section, until it arrives at the current section. So technically, every section is up to the current section is made "active" at some point (hence the console logs of each section name).

Essentially, if you were to go from "Home" to "Contact", it would remove the active class from "Home" and add it to "Portfolio", then remove it from "Portfolio" and add it to "About", before finally removing it from "About" and adding it to "Contact". That way it appears to 'know' what section you're on, but it's actually going through all of them until it reaches the right one.

(Another example: If you went from "Contact" to "Portfolio", it would remove active from "Contact" and add it to "Home", realize it's still not on the right one, then remove active from "Home" and add it to "Portfolio". This probably wouldn't work as well for a site with a bunch of sections, but it appears seamless on smaller/mid-size websites!)

There might be better ways to explain this, but I hope this 'visual' helps!

Its very simple. Your variable section contains all divs with class ".section" as you see the code

Then your "sections" array is filled with all div ids and their scroll positions according to window offset value by using the code

Your sections array will be like this in memory

So when for loop works on sections, it gives the div id like this

for (i in sections) {
    * now "i" gives the id of all div one by one
    }

Meanwhile in this loop querySelector will search anchor tag which contains specific href text

*this will give you specific anchor tag like
    *
    -> 
    -> 
    -> 
    -> 

I hope this will explain you easily.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM