为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

交互式爱情 2021-11-18 16:32:23
我有一个深色菜单,有时会跨越具有相同深色背景的部分,所以我试图切换它的类以在每次跨越深色部分时改变它的颜色。$(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?
查看完整描述

2 回答

?
HUX布斯

TA贡献1876条经验 获得超6个赞

您应该查看Intersection Observer (IO),而不是监听滚动事件。这旨在解决像您这样的问题。它比听滚动事件然后自己计算位置要高效得多。


当然你可以继续只使用滚动事件,W3C的官方 Polyfill使用滚动事件来模拟旧浏览器的 IO。侦听滚动事件和计算位置的性能不高,尤其是在有多个元素的情况下。因此,如果您关心用户体验,我真的建议您使用 IO。只是想添加此答案以显示此类问题的现代解决方案是什么。


我花时间创建了一个基于 IO 的示例,这应该可以帮助您入门。


基本上我定义了两个阈值:一个是 20%,一个是 90%。如果元素在视口中占 90%,则可以假设它将覆盖标题。因此,我将标题的类设置为视图中 90% 的元素。


第二个阈值是 20%,这里我们要检查元素是从顶部还是从底部进入视图。如果它从顶部可见 20%,那么它将与标题重叠。


如您所见,调整这些值并调整逻辑。


编辑:根据您的评论对其进行编辑,请注意,如果您从我的代码中删除 console.log,您可能会看到更好的效果,这样它们就不会干扰您的视图。


我添加了一个标题不变的 div(绿色的)


const sections = document.querySelectorAll('.menu');

const config = {

  rootMargin: '0px',

  threshold: [.2, .9]

};


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

  entries.forEach(entry => {

    console.log(entry); // log the IO entry for demo purposes

    console.log(entry.target); // here you have the Element itself. 

    // you can test for className here for example 

    if (entry.isIntersecting) {

      var headerEl = document.querySelector('header');

      if (entry.intersectionRatio > 0.9) {

        //intersection ratio bigger than 90%

        //-> set header according to target

        headerEl.className=entry.target.dataset.header;      

      } else {

        //-> check if element is coming from top or from bottom into view

        if (entry.target.getBoundingClientRect().top < 0 ) {

          headerEl.className=entry.target.dataset.header;

        }

      } 

    }

  });

}, config);


sections.forEach(section => {

  observer.observe(section);

});

* {

margin: 0;

padding: 0;

box-sizing: border-box;

}


.g-100vh {

height: 100vh

}


header {

  min-height: 50px;

  position: fixed;

  background-color: green;

  width: 100%;

}

  

header.white-menu {

  color: white;

  background-color: black;

}


header.black-menu {

  color: black;

  background-color: white;

}

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>



<header>

 <p>Header Content </p>

</header>

<div class="grid-30-span g-100vh menu" style="background-color:darkblue;" data-header="white-menu">

    <img 

    src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1.414 1'%3E%3C/svg%3E"

    data-src="/images/example_darkblue.jpg" 

    class="lazyload"

    alt="<?php echo $title; ?>">

</div>


<div class="grid-30-span g-100vh no-menu" style="background-color:green;" data-header="black-menu">

    <h1> Here no change happens</h1>

    <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">

    <img 

    src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1.414 1'%3E%3C/svg%3E"

    data-src="/images/example_lightgrey.jpg" 

    class="lazyload"

    alt="<?php echo $title; ?>">

</div>


查看完整回答
反对 回复 2021-11-18
?
海绵宝宝撒

TA贡献1809条经验 获得超8个赞

原因是,然而 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 {

    background-color: #222;

    color: white;

    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>


通过循环这些值来检查您的标题是否穿过它们。


查看完整回答
反对 回复 2021-11-18
  • 2 回答
  • 0 关注
  • 125 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信