Как добавить класс к ссылке, если назначенный носитель находится в области просмотра?

#javascript #jquery #reactjs #intersection-observer

#javascript #jquery #reactjs #пересечение-наблюдатель

Вопрос:

Я закодировал это:

 // Click Function

$('body').on('click', 'a', function() {
  $('a.active').removeClass('active');
  $(this).addClass('active');
});


// Scroll Function

const sectionIsInViewport = document.querySelector('section');

observer = new IntersectionObserver((callback) => {
  console.log('This section is now in the viewport.');
});

observer.observe(sectionIsInViewport);  
 * {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
  font-size: 30px;
  text-decoration: none;
  color: inherit;
}

body {
  display: flex;
  cursor: defau<
}

#left,
#right {
  width: 50%;
  height: 100vh;
  overflow-y: scroll;
  scroll-behavior: smooth;
}

#left {
  background-color: rgb(220, 220, 220);
}

#right {
  background-color: rgb(200, 200, 200);
}

.media {
  padding: 10px;
  padding-bottom: 0;
}

.media:nth-last-child(1) {
  margin-bottom: 10px;
}

img {
  display: block;
  width: 100%;
}

.link {
  cursor: pointer;
}

.active {
  background-color: black;
  color: white;
}  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="left">
  <a class="link active" href="#landscapes">Landscapes</a>
  <a class="link" href="#cats">Cats</a>
  <a class="link" href="#food">Food</a>
</div>

<div id="right">

  <section id="landscapes">
    <article class="media">
      <img src="https://upload.wikimedia.org/wikipedia/commons/8/8d/Freudenberg_sg_Switzerland.jpg">
    </article>
    <article class="media">
      <img src="https://i.pinimg.com/originals/ae/99/54/ae995473d0b73efd9b32b5cd029d9396.jpg">
    </article>
    <div class="media">
      <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/ac/Rural_landscape.JPG/1200px-Rural_landscape.JPG">
    </div>
    <article class="media">
      <img src="https://upload.wikimedia.org/wikipedia/commons/8/8d/Freudenberg_sg_Switzerland.jpg">
    </article>
  </section>

  <section id="cats">
    <article class="media">
      <img src="https://img.webmd.com/dtmcms/live/webmd/consumer_assets/site_images/article_thumbnails/other/cat_relaxing_on_patio_other/1800x1200_cat_relaxing_on_patio_other.jpg">
    </article>
  </section>

  <section id="food">
    <article class="media">
      <img src="https://post.healthline.com/wp-content/uploads/2020/09/healthy-eating-ingredients-1200x628-facebook-1200x628.jpg">
    </article>
    <article class="media">
      <img src="https://theculturetrip.com/wp-content/uploads/2017/07/3566479001_c9707436f9_b.jpg">
    </article>
  </section>

</div>  

В общем, это работает. Но: если вы прокрутите в нужной области, .active ссылка должна обновиться автоматически. Итак, если вы прокрутите, например, до раздела #food , соответствующая ссылка должна быть .active .

Я пытался работать с Intersection Observer, но я не уверен, что это лучший инструмент для этого. И имеет ли смысл работать с React? Если да, то почему?

Кто-нибудь может мне помочь, пожалуйста? Был бы оооочень благодарен. <3<3<3

Ответ №1:

Я думаю, что IntersectionObserver идеально подходит для того, что вы хотите. Как это соответствует вашим потребностям?

 // Click Function

$('body').on('click', 'a', function() {
  $('a.active').removeClass('active');
  $(this).addClass('active');
});


// Scroll Function

const mediaInViewport = document.querySelectorAll('.media');

observer = new IntersectionObserver((entries, observer) => {
  console.log('Next Media in Viewport');
  entries.forEach((entry) => {
    if (entry.target amp;amp; entry.isIntersecting) {
      entry.target.classList.add('active');
      
      const closestParent = entry.target.closest('section');
      if (closestParent) {
        const selector = closestParent.id;
        const links = document.querySelectorAll('.link');
        for (const link of links) {
          const split = link.href.split('#');
          if (split.length >= 2) {
            const local = split[1];
            if (local === selector) {
              link.classList.add('active');
            }
          }
        }
      }
    } 
  });
}, {threshold: 0.7 } );

window.addEventListener('DOMContentLoaded', () => {
  setTimeout( // Wait for images to fully load
      () => {
      mediaInViewport.forEach((item) => {
        observer.observe(item);
      });
    }
  , 1000);
});  
 * {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
  font-size: 30px;
  text-decoration: none;
  color: inherit;
}

body {
  display: flex;
  cursor: defau<
}

#left,
#right {
  width: 50%;
  height: 100vh;
  overflow-y: scroll;
  scroll-behavior: smooth;
}

#left {
  background-color: rgb(220, 220, 220);
}

#right {
  background-color: rgb(200, 200, 200);
}

.media {
  padding: 10px;
  padding-bottom: 0;
}

.media:nth-last-child(1) {
  margin-bottom: 10px;
}

img {
  display: block;
  width: 100%;
}

.link {
  cursor: pointer;
}

.active {
  background-color: black;
  color: white;
}  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="left">
  <a class="link active" href="#landscape">Landscapes</a>
  <a class="link" href="#cats">Cats</a>
  <a class="link" href="#food">Food</a>
</div>

<div id="right">

  <section id="landscape">
    <article class="media">
      <img src="https://upload.wikimedia.org/wikipedia/commons/8/8d/Freudenberg_sg_Switzerland.jpg">
    </article>
    <article class="media">
      <img src="https://i.pinimg.com/originals/ae/99/54/ae995473d0b73efd9b32b5cd029d9396.jpg">
    </article>
    <div class="media">
      <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/ac/Rural_landscape.JPG/1200px-Rural_landscape.JPG">
    </div>
    <article class="media">
      <img src="https://upload.wikimedia.org/wikipedia/commons/8/8d/Freudenberg_sg_Switzerland.jpg">
    </article>
  </section>

  <section id="cats">
    <article class="media">
      <img src="https://img.webmd.com/dtmcms/live/webmd/consumer_assets/site_images/article_thumbnails/other/cat_relaxing_on_patio_other/1800x1200_cat_relaxing_on_patio_other.jpg">
    </article>
  </section>

  <section id="food">
    <article class="media food">
      <img src="https://post.healthline.com/wp-content/uploads/2020/09/healthy-eating-ingredients-1200x628-facebook-1200x628.jpg">
    </article>
    <article class="media food">
      <img src="https://theculturetrip.com/wp-content/uploads/2017/07/3566479001_c9707436f9_b.jpg">
    </article>
  </section>  

Комментарии:

1. Здравствуйте, спасибо за ваш ответ! К сожалению, ссылки с левой стороны не обновляются. Они должны получить класс «.active», если соответствующая область находится в окне просмотра.

2. Привет. Я должен был добавить это сейчас. Однако следует отметить, что это, вероятно, расширяет пределы собственного Javascript. Такие фреймворки, как React или svelte, лучше справились бы с подобным динамическим поведением.

3. Спасибо за обновление! Возможно, это было непонятно: всегда только одна ссылка должна иметь класс «.active». Легко ли это сделать?

4. Я мог бы это сделать. Возможно, это не совсем понятно: этот код является примером того, как это сделать, а не полной программой для удовлетворения ваших конкретных потребностей. Я ожидаю, что вы сможете изменить это самостоятельно, а не ожидать, что я сделаю это за вас.