检测元素何时穿过某个类的任何 div

我有一个深色菜单,有时会跨越具有相同深色背景的部分,所以我试图切换它的类以在每次跨越深色部分时改变它的颜色。


$(window).scroll(function(){

 var fixed = $("section.fixed-header");


 var fixed_position = $("section.fixed-header").offset().top;

 var fixed_height = $("section.fixed-header").height();


 var toCross_position = $(".dark").offset().top;

 var toCross_height = $(".dark").height();


 if (fixed_position + fixed_height  < toCross_position) {

   fixed.removeClass('light-menu');

 } else if (fixed_position > toCross_position + toCross_height) {

   fixed.removeClass('light-menu');

 } else {

   fixed.addClass('light-menu');

 }


});

当我在同一页面内只有一个带有暗类的 div 时,这很好用。但是,如果同一个页面内有多个不同的带有dark类的div,它只会对第一个div起作用。我怎么能在这里包含具有相同暗类的所有其他 div?


交互式爱情
浏览 126回答 2
2回答

HUX布斯

您应该查看Intersection Observer (IO),而不是监听滚动事件。这旨在解决像您这样的问题。它比听滚动事件然后自己计算位置要高效得多。当然你可以继续只使用滚动事件,W3C的官方 Polyfill使用滚动事件来模拟旧浏览器的 IO。侦听滚动事件和计算位置的性能不高,尤其是在有多个元素的情况下。因此,如果您关心用户体验,我真的建议您使用 IO。只是想添加此答案以显示此类问题的现代解决方案是什么。我花时间创建了一个基于 IO 的示例,这应该可以帮助您入门。基本上我定义了两个阈值:一个是 20%,一个是 90%。如果元素在视口中占 90%,则可以假设它将覆盖标题。因此,我将标题的类设置为视图中 90% 的元素。第二个阈值是 20%,这里我们要检查元素是从顶部还是从底部进入视图。如果它从顶部可见 20%,那么它将与标题重叠。如您所见,调整这些值并调整逻辑。编辑:根据您的评论对其进行编辑,请注意,如果您从我的代码中删除 console.log,您可能会看到更好的效果,这样它们就不会干扰您的视图。我添加了一个标题不变的 div(绿色的)const sections = document.querySelectorAll('.menu');const config = {&nbsp; rootMargin: '0px',&nbsp; threshold: [.2, .9]};const observer = new IntersectionObserver(function (entries, self) {&nbsp; entries.forEach(entry => {&nbsp; &nbsp; console.log(entry); // log the IO entry for demo purposes&nbsp; &nbsp; console.log(entry.target); // here you have the Element itself.&nbsp;&nbsp; &nbsp; // you can test for className here for example&nbsp;&nbsp; &nbsp; if (entry.isIntersecting) {&nbsp; &nbsp; &nbsp; var headerEl = document.querySelector('header');&nbsp; &nbsp; &nbsp; if (entry.intersectionRatio > 0.9) {&nbsp; &nbsp; &nbsp; &nbsp; //intersection ratio bigger than 90%&nbsp; &nbsp; &nbsp; &nbsp; //-> set header according to target&nbsp; &nbsp; &nbsp; &nbsp; headerEl.className=entry.target.dataset.header;&nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; //-> check if element is coming from top or from bottom into view&nbsp; &nbsp; &nbsp; &nbsp; if (entry.target.getBoundingClientRect().top < 0 ) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; headerEl.className=entry.target.dataset.header;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; }&nbsp;&nbsp; &nbsp; }&nbsp; });}, config);sections.forEach(section => {&nbsp; observer.observe(section);});* {margin: 0;padding: 0;box-sizing: border-box;}.g-100vh {height: 100vh}header {&nbsp; min-height: 50px;&nbsp; position: fixed;&nbsp; background-color: green;&nbsp; width: 100%;}&nbsp;&nbsp;header.white-menu {&nbsp; color: white;&nbsp; background-color: black;}header.black-menu {&nbsp; color: black;&nbsp; background-color: white;}<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script><header>&nbsp;<p>Header Content </p></header><div class="grid-30-span g-100vh menu" style="background-color:darkblue;" data-header="white-menu">&nbsp; &nbsp; <img&nbsp;&nbsp; &nbsp; src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1.414 1'%3E%3C/svg%3E"&nbsp; &nbsp; data-src="/images/example_darkblue.jpg"&nbsp;&nbsp; &nbsp; class="lazyload"&nbsp; &nbsp; alt="<?php echo $title; ?>"></div><div class="grid-30-span g-100vh no-menu" style="background-color:green;" data-header="black-menu">&nbsp; &nbsp; <h1> Here no change happens</h1>&nbsp; &nbsp; <p>it stays at whatever state it was before, depending on if you scrolled up or down </p></div><div class="grid-30-span g-100vh menu" style="background-color:lightgrey;" data-header="black-menu">&nbsp; &nbsp; <img&nbsp;&nbsp; &nbsp; src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1.414 1'%3E%3C/svg%3E"&nbsp; &nbsp; data-src="/images/example_lightgrey.jpg"&nbsp;&nbsp; &nbsp; class="lazyload"&nbsp; &nbsp; alt="<?php echo $title; ?>"></div>

海绵宝宝撒

原因是,然而 JQuery 选择器选择所有带有.dark类的元素,当你在其上链接.offset().topor.height()方法时,它只会将第一个保存到变量中:var toCross_position = $(".dark").offset().top;var toCross_height = $(".dark").height();您可以将所有位置和高度映射到数组中,然后您还应该使var toCross_position = $(".dark").offset().top;var toCross_height = $(".dark").height();// only the first div's pos and height:console.log(toCross_height, toCross_position);var positions = $('.dark').toArray().map(elem => $(elem).offset().top);var heights = $('.dark').toArray().map(elem => $(elem).height());console.log('all .dark positions:', positions);console.log('all .dark heights:', heights);.dark {&nbsp; &nbsp; background-color: #222;&nbsp; &nbsp; color: white;&nbsp; &nbsp; margin-bottom: 2rem;}<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script><div class="dark">Dark</div><div class="dark">Dark</div><div class="dark">Dark</div><div class="dark">Dark</div>通过循环这些值来检查您的标题是否穿过它们。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript