javascript - 检测元素何时跨越某个类的任何 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 时,这很好用。但是,如果在同一页面内有多个不同的 div 具有暗类,则它仅适用于第一个 div。我怎么能在这里包含所有其他具有相同黑暗类的 div?
解决方案
您应该看看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>
推荐阅读
- python - seaborn.kdeplot (pandas.DataFrame) - ValueError: If using all scalar values, you must pass a index
- git - git - 在致命消息后继续
- flutter - BlocBuilder 更改状态,但不更改屏幕上的文本
- mirroring - 多台 PC 的 VGA 输出在具有切换功能的多台显示器上镜像
- json - 允许用户在有限制的情况下启动 EC2 的 IAM 策略
- flutter - 如何在颤动中更改 AppBar 标题(在图像资产和文本之间)?
- python - Python/Sympy 找到矩阵不是身份的特征值
- python - 如何使用(self)解决构建模型的问题
- azure - 在 Azure DevOps wiki 中嵌入 asciidoc
- python - 更新绘图时出错 + 如何改善其外观