使用 Intersection Observer 根据滚动到视图中的元素的数据属性更改导航栏的主题

Changing theme of nav bar depending on the data attribute of an element scrolled into view using Intersection Observer

我有一个固定的侧边导航栏,默认情况下,它是深色以匹配我页面上最顶部元素的深色,header。

这个深色 header 下面的下一部分有一个白色背景,当它以 50% 的偏移量滚动到视图中时,我想将固定的左侧导航栏更改为相同的颜色。向上滚动时,侧面导航必须再次相应更改。

我曾经使用一个名为 Waypoints by Imakewebthings:

的插件来实现这种效果
var waypoint1 = new Waypoint({
    element: document.getElementById('services-summary'),
        handler: function (direction) {
            if (direction === 'down') {
                // change navigation theme
            } else {
                // change navigation theme
            }
    },
    offset: main_nav_height
});

但是,我试图在不使用任何依赖项的情况下构建这个新项目。因此,我决定使用 Javascript 的原生 Intersection Observer 来尝试实现相同的效果,因为我同意浏览器对此和其他一些视觉效果的支持。

我在获得一个符合上下滚动方向的工作版本时遇到了问题。我还有一个问题,在页面加载时,我将两个部分的主题名称都输出到 JS 控制台,这根本不理想。

这是我要处理的地方:

Javascript:

var intersection_observer_options = {
    root: null,
    rootMargin: '0px',
    threshold: 0
};

var observer = new IntersectionObserver(change_themes_on_view, intersection_observer_options);

function change_themes_on_view(entries, observer) {
    for (var i = 0; i < entries.length; i++) {
        var theme = entries[i].target.getAttribute('data-theme');
        console.log(theme);
    }
}

var themed_sections = document.querySelectorAll('*[data-theme]');
for (var i = 0; i < themed_sections.length; i++) {
    observer.observe(themed_sections[i]);
}

HTML:

我不包括 CSS 方面的事情,因为我可以自己解决。我也没有在此处包括导航栏,因为我只是想演示我是如何识别每个部分的主题的。但是,我在 JSFIDDLE example.

中展示了更多内容
<header data-theme="dark">
    ...
</header>

<main>
    <section data-theme="light">
        ...
    </section>

    <section data-theme="dark">
        ...
    </section>

    <section data-theme="light">
        ...
    </section>

    <section data-theme="dark">
        ...
    </section>
</main>

当我 运行 我的页面时,我在没有滚动任何地方的情况下得到以下控制台输出并且不明白为什么:

> dark
> light
> dark
> light
> dark

为了帮助你帮助我,我整理了一个 FIDDLE 来帮助完成这项工作。

知道这个新的 Intersection Observer API 的人可以帮助我跨过门槛吗?请原谅双关语。

更新 1

I think I have got it working here。仍在修补。

更新 2

是的,it's working

我会添加我自己的答案,因为我相信其他人会发现这个有用而不是删除问题。

我自己修好了,出人意料地差得不远。

为了解决我的两个问题 - 为什么它在控制台中输出所有主题而不考虑滚动方向 - 我只是将这个条件语句添加到我的 change_themes_on_view 函数中:

if (entries[i].intersectionRatio > 0) {
    // do stuff now entry is in viewport
}

测试目标 element/entry 是否在视口内。

这显然修复了脚本在页面加载时将所有目标主题值输出到我的控制台。它现在也尊重方向,因为当目标元素离开视口时,主题就会反转。

现在这是完整的功能:

function change_themes_on_view(entries, observer) {
  for (var i = 0; i < entries.length; i++) {
    if (entries[i].intersectionRatio > 0) {
      var theme = entries[i].target.getAttribute('data-theme');
      nav_bar.setAttribute('data-theme', theme);
    }
  }
}

This is the working demo