对于在滚动上突出显示活动菜单项感到困惑(Vanilla JS)

时间:2017-07-02 19:04:38

标签: javascript

我找到了这个功能,当您滚动到具有相同ID的部分时,它会突出显示活动的菜单锚点。我理解大多数代码是如何工作的,但我不知道窗口onscroll事件如何知道如何使用.active类更新正确的锚标记。

所有的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');
      }
    }
  };
&#13;
&#13;
&#13;

从此Pen:https://codepen.io/zchee/pen/ogzvZZ

这部分让我困惑:

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

我得到setAttribute在锚标记中添加了一个活动类 - 但是当滚动时querySelector如何找到要更新的正确锚?

我尝试从(for for array循环)中记录索引变量[i]以获取当前节的id(onscroll),但它返回当前滚动位置(作为数字)。

这就是为什么我不明白为什么插入&#39; i&#39;变量here:('a[href*=' + i + ']')表示onscroll事件中对应的section id。

我想我并不能真正了解这个forEach功能是如何运作的:

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

我得到它循环遍历所有部分并将sections[e.id]推送到稍后在onscroll事件中使用的空对象sections = {} - 但这是我的理解停止的地方。 : - /

抱歉,我不知道如何更好地表达这个问题。我花了好几个小时试图绕过它。我无法找到与此类似的任何主题示例,但我希望在我在任何地方使用它之前了解它是如何工作的。

非常感谢一些反馈! : - )

2 个答案:

答案 0 :(得分:1)

根据W3学校的documentation.querySelector获取文档中的第一个元素,其中class等于被搜索的元素。

a[href*=#]表示querySelector正在查找包含#的所有元素,在您的情况下'a[href*=' + i + ']'进一步指定具有href i的元素}}

所以当你把所有东西拼凑起来时,代码

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

查找具有等于当前&#39; i&#39;的href的元素。 section,并将该属性类设置为该元素的活动状态。

希望它有所帮助!

修改

每当滚动窗口时,都会发生以下情况:

  1. 1)设置一个名为scrollPosition的变量,该变量设置为等于 documentElement&#34; s&#34;最高&#34; point(或scrollTop) OR 文件机构&#34;最高&#34; point(或scrollTop)
  2. 然后,所有部分中的i: 如果该部分小于或等于scrollPostition,它会将先前活动的类更改为null,并将当前部分的类设置为活动状态。
  3. 然后对每个部分重复,直到它到达当前部分。所以从技术上讲,每个部分都取决于当前部分的制作和活动的#34;在某些时候(因此每个部分名称的控制台日志)。

    基本上,如果你要从&#34; Home&#34;到&#34;联系&#34;,它会删除&#34; Home&#34;并将其添加到&#34;投资组合&#34;,然后将其从&#34;投资组合&#34;并将其添加到&#34;关于&#34;,最后将其从&#34;关于&#34;并将其添加到&#34;联系&#34;。这样它似乎“知道”。你在哪个部分,但它实际上经历了所有部分,直到它到达正确的部分。

    (另一个例子:如果您从&#34;联系&#34;到&#34;投资组合&#34;,它将从&#34;联系&#34;中删除活动,并将其添加到&#34; Home&#34;,意识到它仍然没有在正确的那个,然后从&#34; Home&#34;中删除活动并将其添加到&#34; Portfolio&#34;。这可能不会也适用于有大量部分的网站,但在中小型网站上看起来无缝!)

    可能有更好的方法来解释这个问题,但我希望这可以通过视觉方式解决这个问题。帮助!

答案 1 :(得分:1)

非常简单。 当你看到代码

时,你的变量部分包含所有带有“.section”类的div

    var section = document.querySelectorAll(".section");

然后你的“sections”数组使用代码

根据窗口偏移值填充所有div id及其滚动位置

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

你的sections数组在内存中会是这样的


    
    sections['home']=position of home 
    sections['portfolio']=position of portfolio
    sections['about']=position of about
    sections['contact']=position of contact
    

因此,当for循环在部分上工作时,它会给出像这样的div id


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

同时在此循环中,querySelector将搜索包含特定href文本的锚标记


    *this will give you specific anchor tag like
    *document.querySelector('a[href*='home']')
    -> a[href*='home']
    -> a[href*='portfolio']
    -> a[href*='about']
    -> a[href*='contact']

我希望这会很容易解释你。