【问题标题】:javascript trigger event when div at top of parent div当div位于父div顶部时的javascript触发事件
【发布时间】:2020-01-19 09:30:02
【问题描述】:

当 ID 到达父 div 的顶部时,我想用 vanilla javascript 触发一个事件。已经看到使用 jQuery 进行此类操作的示例,但我不想为简单的效果加载那么多。另外,大多数示例都处理视口的顶部,而我的主 div 大约是视口高度的 90%,上面有一个 info div。

我正在处理一个包含多个部分的长网页,该网页在主 div 中滚动。当每个部分的标题<h2 id="title1">bla bla bla</h2> 到达主 div 的顶部时,我想触发 info div 中显示的标题<div id="info1">bla bla bla</div> 的简单显示/隐藏。显示/隐藏很简单:

 function chngInfo(x) {
    const targets = document.querySelectorAll('[id^="info"]');
    for (let i = targets.length; i--;) {
      targets[i].style.display = 'none';
    }
    document.getElementById('info' + x).style.display = 'block';
  }

它触发了让我受阻的功能。更复杂的情况是主 div 的高度因设备而异,因此不能轻易地根据视口高度进行公式计算。

如果单个函数可以在向下滚动时通过顶部或在向上滚动时通过底部时查找任何 titleX,那将是主要的好处。

【问题讨论】:

  • 我不确定我是否理解你...当用户滚动到顶部时,你需要用元素触发事件吗?
  • 是的,当页面上的<h2 id="titleX"> 之一到达顶部时,我想为相关的 infoX 触发 chngInfo 函数
  • 我想知道“交叉路口观察员”是否会有所帮助?

标签: javascript css scroll


【解决方案1】:

我认为有两种方法可以实现:

  • 首先:使用带有offsetTop , scrollY 属性的scroll 事件来获得您需要达到的点......但它有一些性能问题:

var myTarget = document.querySelector('.target')

window.addEventListener('scroll', function() {
  if(myTarget.offsetTop - window.scrollY <= 0){
    myTarget.style.color = "red"
  }
})
<h1>hello</h1>
<h1>hello</h1>
<h1>hello</h1>
<h1>hello</h1>
<h1>hello</h1>
<h1>hello</h1>
<h1>hello</h1>
<h1>hello</h1>
<h1>hello</h1>
<h1>hello</h1>
<h1 class='target'>Target elemnt example</h1>
<h1>hello</h1>
<h1>hello</h1>
<h1>hello</h1>
<h1>hello</h1>
<h1>hello</h1>
<h1>hello</h1>
<h1>hello</h1>
<h1>hello</h1>
<h1>hello</h1>
<h1>hello</h1>
  • 秒:使用intersection Observer

这个链接有很好的解释和例子: https://webdesign.tutsplus.com/tutorials/how-to-intersection-observer--cms-30250

【讨论】:

  • IntersectionObserver 成功了,感谢您为我指明了方向。
【解决方案2】:

我将scroll event listener 与一些节流结合使用,以避免在侦听滚动事件时出现一些性能缺陷。

如果您运行下面的 sn-p,您会注意到它为您提供了一个挂钩,您可以在其中调用一些仅在元素到达视口顶部时才调用一次的逻辑。如果用户向上滚动,它将重置。

我还在代码中留下了一些 cmets 以防万一。

// from 
// @peduarte 
// https://gist.github.com/peduarte/969217eac456538789e8fac8f45143b4
function throttle(func, wait = 100) {
  let timer = null;
  return function(...args) {
    if (timer === null) {
      timer = setTimeout(() => {
        func.apply(this, args);
        timer = null;
      }, wait);
    }
  };
}

// throttle scroll by this much (ms)
const SCROLL_THROTTLE = 200;

// get our elements
const wrapper = document.querySelector('.wrapper');
const target = document.querySelector('.this-one');

// reserve this so we can overwrite it later
let reachedTop;

// function that fires when we scroll
const checkOffset = () => {
  // get out offsets
  const wrapperOffset = wrapper.scrollTop + wrapper.offsetTop;
  const targetOffset = target.offsetTop;
  // try to do some work
  if (wrapperOffset >= targetOffset && !reachedTop) {
    reachedTop = true;
    // element reached top do more work...
    console.log(reachedTop);
  } else if (wrapperOffset <= targetOffset && reachedTop) {
    reachedTop = false;
    // user scrolled up and element longer at top...
    console.log(reachedTop);
  }
}

// throttle our function
const throttledScroll = throttle(checkOffset, SCROLL_THROTTLE);

// call the throttled function when we scroll
wrapper.addEventListener('scroll', throttledScroll);
.this-one {
  color: blue;
}

.wrapper {
  border: 1px solid red;
  height: 50vh;
  overflow: auto;
  margin-top: 2em;
  padding: 2em;
  display: inline-block;
}
<div class="wrapper">

  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p class="this-one">Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>
  <p>Example</p>

</div>

【讨论】:

    【解决方案3】:

    对需求不是很清楚。 我觉得你可以试试

    1. getBoundingClientRect 决定显示哪些内容
    2. 检测滚动停止事件,仅供参考link

    希望对你有帮助,谢谢。

    function entry() {
      // 1. detect the main bound
      const mainRect = document.querySelector('#main').getBoundingClientRect();
      console.log('main', mainRect.y);
    
      // 2. get all the title
      const titles = document.querySelectorAll('h2');
      // hideAll
      titles.forEach(t => {
        t.nextElementSibling.style.display = 'none';
      });
      const first = Array.from(titles).find((t, i) => {
        const rect = t.getBoundingClientRect();
        rect.y > 0 && console.log('show', i);
        return rect.y > 0;
      });
      window.t = first;
      first.nextElementSibling.style.display = 'block';
    
    }
    
    var timer = null;
    window.addEventListener('scroll', function() {
        if(timer !== null) {
            clearTimeout(timer);
        }
        timer = setTimeout(entry, 150);
    }, false);
    
    
    // init show;
    entry();
    <html>
    <style>
      #main {
        background: green;
        height: 1800px;
      }
      #info1 {
        display: none;
      }
      h2 {
        height: 150px;
      }
      div {
        height: 500px;
        background: red;
      }
    </style>
      <body>
        <div id="main">
        <h2 id="title1">bla bla bla</h2>
        <div id="info1">bla bla bla</div>
        <h2 id="title1">bla bla bla</h2>
        <div id="info1">bla bla bla</div>
        <h2 id="title1">bla bla bla</h2>
        <div id="info1">bla bla bla</div>
        <h2 id="title1">bla bla bla</h2>
        <div id="info1">bla bla bla</div>
        <h2 id="title1">bla bla bla</h2>
        <div id="info1">bla bla bla</div>
        <h2 id="title1">bla bla bla</h2>
        <div id="info1">bla bla bla</div>
        <h2 id="title1">bla bla bla</h2>
        <div id="info1">bla bla bla</div>
        <h2 id="title1">bla bla bla</h2>
        <div id="info1">bla bla bla</div>
        <h2 id="title1">bla bla bla</h2>
        <div id="info1">bla bla bla</div>
        <h2 id="title1">bla bla bla</h2>
        <div id="info1">bla bla bla</div>
        <h2 id="title1">bla bla bla</h2>
        <div id="info1">bla bla bla</div>
        <h2 id="title1">bla bla bla</h2>
        <div id="info1">bla bla bla</div>
        </div>
      </body>
    </html>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-06-26
      • 1970-01-01
      • 1970-01-01
      • 2015-09-21
      • 1970-01-01
      • 2012-05-09
      • 1970-01-01
      相关资源
      最近更新 更多