Проверьте, виден ли элемент в окне просмотра - PullRequest
0 голосов
/ 23 апреля 2020

Я попробовал несколько способов сделать это сейчас, я на 80%, но это все еще не совсем там. У меня есть разделы разных размеров. И моя навигация, в которой я пытаюсь добавить активный класс, когда я нахожусь в соответствующем разделе, показывая, что он активен.

Код имеет тенденцию быть глючным, внутри nav-галереи, у меня есть Галерея кладки и скользкий слайдер. Я не уверен, влияет ли это на это. Но активный класс имеет тенденцию придерживаться галереи, навигации. Каждая секция имеет высоту не менее 100vh.

В соответствии с предложением Cedri c, я попытался с помощью API наблюдателя пересечения . Но у него та же проблема, по крайней мере, в моей реализации, он глючит, и галерея как-то активна, даже когда отсутствует в окне просмотра.

  let options = {
    root: null,
    rootMargin: '0px',
    threshold: 1
  }
  let callback = (entries, observer) => {
      console.log("callback called");
    entries.forEach(entry => {
        console.log("set active for " + entry.target.id);
        let sectionId = entry.target.id;
        navItems.each(function(){
            $(this).removeClass('active');
        });
        $("a[href='#" + sectionId + "']").addClass('active');
    });
  };

  let observer = new IntersectionObserver(callback, options);

  pageSections.each(function () {
    let target = document.querySelector("#" + $(this).attr('id'));
    observer.observe(target);
  });

const navItems = $(".navigation-item");
const pageSections = $(".section-page");

const elementIsInView = el => {
    const scroll = window.scrollY || window.pageYOffset
    const boundsTop = el.getBoundingClientRect().top + scroll

    const viewport = {
        top: scroll,
        bottom: scroll + window.innerHeight,
    }

    const bounds = {
        top: boundsTop,
        bottom: boundsTop + el.clientHeight,
    }

    return ( bounds.bottom >= viewport.top && bounds.bottom <= viewport.bottom ) 
        || ( bounds.top <= viewport.bottom && bounds.top >= viewport.top );
}
$(function () {
    $(window).scroll(function () {
        pageSections.each(function () {
            console.log("elements to check " + $(this).attr('id'))
            if(elementIsInView($(this)[0])){
                console.log("element is in viewport " + $(this).attr('id'))
                // this = the section that is visible
                let sectionId = $(this).attr('id');
                navItems.each(function(){
                    $(this).removeClass('active');
                });
                $("a[href='#" + sectionId + "']").addClass('active');
            }
        })
    })
})   
.section-page{
  height:100vh;
}
.navigation-fixed{
  position:fixed;
  top:20px;
  left:20px;
}
.navigation-fixed ul li a.active{
  color:red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<nav class="navigation-fixed">
        <ul>
            <li>
                <a href="#nav-contact" class="navigation-item">CONTACT</a>
            </li>
            <li>
                <a href="#nav-info" class="navigation-item">INFO</a>
            </li>
            <li>
                <a href="#nav-gallery" class="naviation-item">GALLERY</a>
            </li>
            <li>
                <a href="#nav-home" class="navigation-item active">Home</a>
            </li>
        </ul>
    </nav>
    
    <section class="section-page" id="nav-gallery">Content here</section>
<section class="section-page" id="nav-info">Content here</section>
<section class="section-page" id="nav-contact">Content here</section>

Ответы [ 2 ]

0 голосов
/ 24 апреля 2020

Вот небольшой / базовый c пример использования Intersection Observer Надеюсь, это поможет

// list of elements to be observed
const targets = document.getElementsByClassName('section-page')

const options = {
  root: null, // null means root is viewport
  rootMargin: '0px',
  threshold: 0.5 // trigger callback when 50% of the element is visible
}


function callback(entries, observer) { 
  entries.forEach(entry => {

    if(entry.isIntersecting){
    	document.querySelector('.active').classList.remove('active');
      const sectionId = entry.target.id; // identify which element is visible in the viewport at 50%
      document.querySelector(`[href="#${sectionId}"]`).classList.add('active');
      
    }
  });
};

let observer = new IntersectionObserver(callback, options);

[...targets].forEach(target => observer.observe(target));
body {
  margin: 0;
}

main {
  margin: 0;
  display: grid;
  grid-template-columns: 150px 1fr;
  font-family: sans-serif; 
}

#nav {
    list-style-type: none;
}

.navigation-item {
    color: inherit;
    text-decoration: none;
    display: block;
    margin-bottom: 12px;
    padding: 5px;
}

.navigation-item.active {
  background-color: grey;
  color: white;
  font-weight: bold;
}


#sections {
  height: 100vh;
  overflow: auto;
}

.section-page {
  margin: 20px;
  height: 100vh;
  box-sizing: border-box;
  padding: 0 20px 20px;
}

.section-page:nth-child(1) {
  background-color: crimson;
}

.section-page:nth-child(2) {
  background-color: darkgreen;
}

.section-page:nth-child(3) {
  background-color: darkorange;
}

.section-page:nth-child(4) {
  background-color: darkblue;
}

.content {
  padding-top: 20px;
  color: white;
  position: sticky;
  top: 0;
}
<main>
  <nav>
    <ul id="nav">
      <li>
        <a href="#nav-home" class="navigation-item active">HOME</a>
      </li>
      <li>
        <a href="#nav-gallery" class="navigation-item">GALLERY</a>
      </li>
      <li>
        <a href="#nav-info" class="navigation-item">INFO</a>
      </li>
      <li>
        <a href="#nav-contact" class="navigation-item">CONTACT</a>
      </li>
      
    </ul>
  </nav>
  <div id="sections">
    <section class="section-page" id="nav-home">
      <div class="content">Home section</div>
    </section>
    <section class="section-page" id="nav-gallery">
      <div class="content">Gallery section</div>
    </section>
    <section class="section-page" id="nav-info">
      <div class="content">Info section</div>
    </section>
    <section class="section-page" id="nav-contact">
      <div class="content">Contact section</div>
    </section>
  </div>
</main>
0 голосов
/ 24 апреля 2020

Все выглядит нормально с вашим кодом, за исключением неправильного написания класса для GALLERY. Как только это исправлено, оно больше не липкое.

В общем, когда вы готовы предоставить нам такой код (спасибо, кстати, это было очень полезно), было бы здорово, если бы вы могли сделать один из StackOverflows специальным HTML + JS + CSS фрагменты. Он показывает весь код так же, как вы, но также позволяет запускать этот код и мгновенно копировать его в ответ, где его можно немного отредактировать. Я использовал такой фрагмент для ответа:

const navItems = $(".navigation-item");
const pageSections = $(".section-page");

const elementIsInView = el => {
    const scroll = window.scrollY || window.pageYOffset
    const boundsTop = el.getBoundingClientRect().top + scroll

    const viewport = {
        top: scroll,
        bottom: scroll + window.innerHeight,
    }

    const bounds = {
        top: boundsTop,
        bottom: boundsTop + el.clientHeight,
    }

    return ( bounds.bottom >= viewport.top && bounds.bottom <= viewport.bottom ) 
        || ( bounds.top <= viewport.bottom && bounds.top >= viewport.top );
}
$(function () {
    $(window).scroll(function () {
        pageSections.each(function () {
            if(elementIsInView($(this)[0])){
                // this = the section that is visible
                let sectionId = $(this).attr('id');
                navItems.each(function(){
                    $(this).removeClass('active');
                });
                $("a[href='#" + sectionId + "']").addClass('active');
            }
        })
    })
})   
.section-page {
  height: 100vh;
}

.active {
  color: red;
}

.navigation-fixed {
  position: fixed;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<nav class="navigation-fixed">
  <ul>
    <li>
      <a href="#nav-contact" class="navigation-item">CONTACT</a>
    </li>
    <li>
      <a href="#nav-info" class="navigation-item">INFO</a>
    </li>
    <li>
      <a href="#nav-gallery" class="navigation-item">GALLERY</a>
    </li>
    <li>
      <a href="#nav-home" class="navigation-item active">Home</a>
    </li>
  </ul>
</nav>

<section class="section-page">Spacing</section>

<section class="section-page" id="nav-gallery">gallery here</section>
<section class="section-page">Spacing</section>

<section class="section-page" id="nav-info">info here</section>

<section class="section-page">Spacing</section>

<section class="section-page" id="nav-contact">contact here</section>
<section class="section-page">Spacing</section>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...