首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使相交观察者复制引导滚动间谍行为

如何使相交观察者复制引导滚动间谍行为
EN

Stack Overflow用户
提问于 2020-01-01 23:36:34
回答 1查看 1.3K关注 0票数 2

我正在构建一个blazor应用程序,在这个应用程序中,我应该将java脚本代码保持在最少。所以我在我的视差页面中只使用了引导css。我已经用window.onscroll实现了类似滚动间谍的行为,因为到目前为止还不能用c#完成它;但它的性能很差。

在谷歌搜索之后,我最近偶然发现了IntersectionObserver应用编程接口。所以我想让我现有的window.onscroll逻辑与IntersectionObserver应用程序接口一起工作。然而,我无法做到这一点。

这就是我想要做的。在我的视差页面固定顶部导航栏,我想应用active css类到a.nav-items时,用户滚动达到各自的部分,他想查看。

下面是HTML:

代码语言:javascript
复制
<body data-spy="scroll" data-target=".site-nav" data-offset="55">

  <header id="page-hero" class="site-header d-flex flex-column align-content-between">

    <nav class="site-nav family-sans navbar navbar-expand-md navbar-dark fixed-top">
      <div class="container-fluid">

        <button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#myTogglerNav" aria-controls="myTogglerNav"
          aria-label="Toggle Navigation">
          <span class="navbar-toggler-icon"></span>
        </button>

        <a class="navbar-brand text-uppercase" href="#page-hero">
          <i class="fas fa-cube mr-2"></i> Layout Components</a>

        <div class="collapse navbar-collapse" id="myTogglerNav">
          <div class="navbar-nav ml-auto font-weight-regular text-uppercase">
            <a class="nav-item nav-link" href="#page-hero">home</a>
            <a class="nav-item nav-link" href="#page-multicolumn">columns</a>
            <a class="nav-item nav-link" href="#page-media">media</a>
            <a class="nav-item nav-link" href="#page-photogrid">grid</a>
            <a class="nav-item nav-link" href="#page-carousel">carousel</a>
            <a class="nav-item nav-link" href="#page-nested">nested</a>
            <a class="nav-item nav-link" href="#page-icons">icons</a>
            <a class="nav-item nav-link" href="#page-floater">floater</a>
            <a class="nav-item nav-link" href="#page-cards">cards</a>
          </div>
        </div>

      </div>
    </nav>

    <section class="layout-hero jumbotron jumbotron-fluid d-flex align-items-center mt-5 text-reverse">
      <div class="container text-center">
......
......
......

    <article id="page-multicolumn" class="page-section vertical-padding">

    <header class="page-section-header container">
.....
.....
.....

    <article id="page-media" class="page-section vertical-padding">

    <header class="page-section-header container text-center">
....

我在顶部.nav-item中有与ahref匹配的idarticle标签。我只粘贴了几个html的骨架是相同的所有文章的标签。

这是我现有的window.onscroll

代码语言:javascript
复制
var sections = {};

document.querySelectorAll(".page-section,.site-header").forEach(section => sections[section.id] = section.offsetTop);

window.onscroll = function () {
    document.querySelector('header nav').classList.toggle('inbody', document.documentElement.scrollTop > 380);
    document.querySelector('#page-media .layout-animation').style['visibility'] = 'hidden';

    var scrollPosition = document.documentElement.scrollTop || document.body.scrollTop;

    Object.keys(sections).forEach(key => {
        if (sections[key] <= scrollPosition + 55) {
            document.querySelectorAll('a.nav-item').forEach(a => a.classList.remove('active'));
            document.querySelector('a[href="#' + key + '"]').classList.add('active');

            if (key === 'page-media') {
                document.querySelector('#page-media .layout-animation').classList.add('animated', 'fadeInRight');
            }
        }
    });
};

上面的代码可以工作。但是我想使用正确的API。

这是我的IntersectionObserver

代码语言:javascript
复制
if (window.IntersectionObserver) {
    let observer = new IntersectionObserver(
        (entries, observer) => {
            console.log(entries);
            entries.forEach(entry => {
                /* Here's where we deal with every intersection */
                document.querySelectorAll('a.nav-item').forEach(a => a.classList.remove('active'));
                if (entry.isIntersecting) {
                    document.querySelector('header nav').classList.toggle('inbody', entry.target.id !== 'page-hero');
                    document.querySelector('#page-media .layout-animation').style['visibility'] = 'hidden';
                    document.querySelector('a[href="#' + entry.target.id + '"]').classList.add('active');
                    if (entry.target.id === 'page-media') {
                        document.querySelector('#page-media .layout-animation').classList.add('animated', 'fadeInRight');
                    }
                }
            });
        }, { root: document.querySelector('.site-nav'), rootMargin: "0px", threshold: 0 });
    document.querySelectorAll('.page-section,.site-header').forEach(section => observer.observe(section));
}

但是我的交叉口观察器不工作。我试着使用console.log(entry)来看看会发生什么。所有的条目只在页面加载时被记录下来,并且在那之后就不工作了。请在我错的地方提供帮助。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-01-18 11:32:10

这里的代码不能工作的原因是它在错误的时间运行。对document.querySelectorAll('.page-section,.site-header')的调用需要在这些元素被呈现到DOM中之后执行,否则它将不会匹配任何内容。

这是我是如何工作的,我稍微调整了一下函数,如下所示,

代码语言:javascript
复制
function highlightMenu() {
    const sections = document.querySelectorAll('.page-section,.site-header');
    const config = {
        rootMargin: '-55px 0px -85%'
    };

    let observer = new IntersectionObserver(function
        (entries, self) {

        entries.forEach(entry => {
            if (entry.isIntersecting) {
                intersectionHandler(entry);
            }
        });
    }, config);

    sections.forEach(section => observer.observe(section));
}

function intersectionHandler(entry) {
    const id = entry.target.id;
    document.querySelector('header nav').classList.toggle('inbody', id !== 'page-hero');
    if (id === 'page-media') {
        document.querySelector('#page-media .layout-animation').classList.add('animated', 'fadeInRight');
    }

    const currentlyActive = document.querySelector('nav a.nav-item.active');
    const shouldBeActive = document.querySelector('nav a.nav-item[href="#' + id + '"]');

    if (currentlyActive) {
        currentlyActive.classList.remove('active');
    }
    if (shouldBeActive) {
        shouldBeActive.classList.add('active');
    }
}

并使用blazor中的JS互操作从我的组件OnAfterRenderAsync内部调用,

代码语言:javascript
复制
@code{

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await JSRuntime.InvokeVoidAsync("highlightMenu");
        }
    }

}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59553761

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档