当 div 位于父 div 顶部时,JavaScript 触发事件



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

我正在使用一个很长的网页,有几个部分,在主div中滚动。 当每个部分的标题<h2 id="title1">bla bla bla</h2>到达主div的顶部时,我想触发信息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,那将是主要的好处。

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

  • 首先:使用具有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

我将滚动事件侦听器与一些限制结合使用,以避免侦听滚动事件的一些性能陷阱。

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

我还在代码中留下了一些注释,以防万一。

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

不太清楚需求。 我想你可以试试

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

希望有帮助,谢谢。

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>

最新更新