【问题标题】:Intersection Observer fine tuning for different window sizesIntersection Observer 针对不同窗口大小进行微调
【发布时间】:2021-02-11 05:08:22
【问题描述】:

这是我目前的代码:

const mediaInViewport = document.querySelectorAll('.media');
const links = Array.from(document.querySelectorAll('.link'));
let actLink = links[0];

document.body.addEventListener('click', (event) => {
  if (event.target.tagName === 'a') {
    actLink.classList.remove('active');
    actLink = links.find(link => event.target.href === link.href)
    actLink.classList.add('active');
  }
}, false)

observer = new IntersectionObserver((entries, observer) => {
  entries.forEach((entry) => {
    if (entry.target && entry.isIntersecting) {
      const closestParent = entry.target.closest('section');
      if (closestParent) {
        actLink.classList.remove('active');
        actLink = links.find(link =>
          link.href.slice(link.href.lastIndexOf('#')) === `#${closestParent.id}`
        )
        actLink.classList.add('active');
      }
    }
  });
}, {
  threshold: 0
});

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: default;
}

#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="#beer">Beer</a>
  <a class="link" href="#food">Food</a>
</div>
<div id="right">
  <section id="landscape">
    <div class="media">
      <img src="https://upload.wikimedia.org/wikipedia/commons/8/8d/Freudenberg_sg_Switzerland.jpg">
    </div>
    <div class="media">
      <img src="https://upload.wikimedia.org/wikipedia/commons/8/8d/Freudenberg_sg_Switzerland.jpg">
    </div>
  </section>
  <section id="cats">
    <article class="media">
      <img src="https://upload.wikimedia.org/wikipedia/commons/b/b8/Cute_cat_%281698598876%29.jpg">
    </article>
    <article class="media">
      <img src="https://upload.wikimedia.org/wikipedia/commons/b/b8/Cute_cat_%281698598876%29.jpg">
    </article>
  </section>
  <section id="beer">
    <article class="media beer">
      <img src="https://upload.wikimedia.org/wikipedia/commons/8/89/Craft_Beer_at_the_Taedonggang_Microbrewery_No._3_%2812329931855%29.jpg">
    </article>
  </section>
  <section id="food">
    <article class="media food">
      <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/6/6d/Good_Food_Display_-_NCI_Visuals_Online.jpg/1200px-Good_Food_Display_-_NCI_Visuals_Online.jpg">
    </article>
  </section>
</div>

观察功能应该适用于所有窗口大小。目前,如果窗口大小稍大一些,例如“啤酒”链接如果您单击它或滚动太不敏感,则不会收到 .active 类。

有没有办法解决这个问题?

需要如下规则:

  1. 始终只有最后观察到的对象会触发.active 类。
  2. 但是:如果在某一点有不同的可观察对象可见 (例如点击链接“啤酒”后),然后“最 占主导地位的“一个(未被切断且最存在的那个)应该 触发.active 类。

我会非常感谢您的帮助!

【问题讨论】:

    标签: javascript intersection intersection-observer


    【解决方案1】:

    const mediaInViewport = Array.from(document.querySelectorAll('.media'));
    const sections = Array.from(document.querySelector('#right').children);
    const links = Array.from(document.querySelectorAll('.link'));
    let actLink = links[0];
    let actSection = null;
    let targetLink = null;
    let targetSection = null;
    
    document.body.addEventListener('click', (event) => {
      if (event.target.tagName === 'A') {
        event.preventDefault();
        targetLink = event.target;
        targetSection = sections.find(section => section.id ===  targetLink.href.slice(targetLink.href.lastIndexOf('#')+1))
        location.hash = targetLink.href.slice(targetLink.href.lastIndexOf('#'));
        actLink.classList.remove('active');
        actLink = links.find(l => event.target.href === l.href)
        actLink.classList.add('active');
    
      }
    }, false)
    
    observer = new IntersectionObserver((entries, observer) => {
      entries.forEach((entry) => {
        if (entry.target && entry.isIntersecting) {
          const closestParent = entry.target.closest('section');
          if (closestParent) {
            actLink.classList.remove('active');
            if (!targetLink) {
              actLink = links.find(link =>
                link.href.slice(link.href.lastIndexOf('#')) === `#${closestParent.id}`
              ) 
            } else {
              if (closestParent === targetSection){
                targetLink = null 
              }
            }
            actSection = sections.find(section => section.id ===  actLink.href.slice(actLink.href.lastIndexOf('#')))
            actLink.classList.add('active');
          }
        }
      });
    }, {
      threshold: 0.3
    });
    
    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;
    }
    
    body {
      display: flex;
      cursor: default;
    }
    
    #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:active {
      cursor: pointer;
    }
    
    a:target {
      background-color: black;
      color: white;
    }
    
    a {
      text-decoration: none;
      color: inherit;
    }
    
    
    
    section:target {
      background-color: black;
      color: white;
    }
    
    
    .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="#beer">Beer</a>
          <a class="link" href="#food">Food</a>
        </div>
        <div id="right">
          <section id="landscape">
            <div class="media">
              <img src="https://upload.wikimedia.org/wikipedia/commons/8/8d/Freudenberg_sg_Switzerland.jpg">
            </div>
            <div class="media">
              <img src="https://upload.wikimedia.org/wikipedia/commons/8/8d/Freudenberg_sg_Switzerland.jpg">
            </div>
          </section>
          <section id="cats">
            <article class="media">
              <img src="https://upload.wikimedia.org/wikipedia/commons/b/b8/Cute_cat_%281698598876%29.jpg">
            </article>
            <article class="media">
              <img src="https://upload.wikimedia.org/wikipedia/commons/b/b8/Cute_cat_%281698598876%29.jpg">
            </article>
          </section>
          <section id="beer">
            <article class="media beer">
              <img src="https://upload.wikimedia.org/wikipedia/commons/8/89/Craft_Beer_at_the_Taedonggang_Microbrewery_No._3_%2812329931855%29.jpg">
            </article>
          </section>
          <section id="food">
            <article class="media food">
              <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/6/6d/Good_Food_Display_-_NCI_Visuals_Online.jpg/1200px-Good_Food_Display_-_NCI_Visuals_Online.jpg">
            </article>
          </section>
        </div>

    【讨论】:

    • 塔安克斯!我觉得现在好多了。但是,如果窗口大小处于类似全景的方向,并且无论如何图像都会被截断,那么只有在设置“阈值:0”时它才能正常工作。在所有其他情况下,“阈值:0”会破坏函数。你有解决这个问题的想法吗?
    • 不,我还没有……但我会考虑的。
    • 也许带有媒体查询的 css 会有所帮助,,,
    • 您也可以根据方向更改阈值stackoverflow.com/questions/4917664/…
    • 我有一些改进代码的想法,但我会先检查一下
    猜你喜欢
    • 2021-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-28
    • 1970-01-01
    • 2022-08-11
    相关资源
    最近更新 更多