javascript - 在滚动时突出显示侧边栏项目
问题描述
简单地说,我有一个带有类别列表的侧边栏。在正文中,我列出了许多卡片,其中每张卡片对应于侧边栏列表中的一个类别。
目标:当我滚动页面时,我希望在侧边栏中突出显示正确的类别。
尝试:我在这个CodePen中尝试了一段时间,但不知何故,我似乎无法做到恰到好处。
这是我的代码:
/* Menu - Show active */
const newsItems = document.querySelectorAll('.item');
function highlightMenuItem() {
newsItems.forEach((el) => {
let bounding = el.getBoundingClientRect();
let elementHeight = el.offsetHeight / 2;
if (bounding.top >= 0 && bounding.bottom <= (window.innerHeight || document.documentElement.clientHeight) + elementHeight) {
let activeMenu = el.getAttribute('data-category');
document.querySelector('.' + activeMenu).classList.add('menu-active');
console.log(document.querySelectorAll('.menu-active'));
if (document.querySelectorAll('.menu-active').length > 1) {
document.querySelectorAll('.menu-active')[0].classList.remove('menu-active');
}
} else {
let inActiveMenu = el.getAttribute('data-category');
if (document.querySelector('.' + inActiveMenu).classList.contains('menu-active')) {
document.querySelector('.' + inActiveMenu).classList.remove('menu-active');
}
}
});
}
document.addEventListener('scroll', function() {
window.requestAnimationFrame(function() {
highlightMenuItem();
});
});
* {
box-sizing: border-box;
}
.menu__list {
background-color: #fff;
display: flex;
box-sizing: border-box;
flex-direction: column;
justify-content: space-around;
position: fixed;
top: 0;
bottom: 0;
right: 0;
width: 50px;
}
.menu__item {
border: solid 1px #000;
flex: 1 1 0;
border-top: none;
text-align: center;
transition: all .3s;
a {
font-weight: 300;
font-size: 10px;
line-height: 1.8;
letter-spacing: -0.2px;
height: 100%;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
span {
transform: rotate(-90deg);
display: block;
}
&.menu-active {
color: #fff;
background: #000;
}
}
.wrapper {
display: grid;
padding-right: 50px;
grid-template-columns: 1fr 1fr 1fr;
}
.item {
text-align: center;
border: solid 1px #000;
height: 200px;
display: flex;
justify-content: center;
align-items: center;
}
<div class="menu__list">
<div class="next-space menu__item">
<a href="{{link_url::288}}#next-space"><span>Space</span></a>
</div>
<div class="next-intelligence menu__item">
<a href="{{link_url::288}}#next-intelligence"><span>Intelligence</span></a>
</div>
<div class="next-mobility menu__item">
<a href="{{link_url::288}}#next-mobility"><span>Mobility</span></a>
</div>
<div class="next-security menu__item">
<a href="{{link_url::288}}#next-security"><span>Security</span></a>
</div>
<div class="next-medtech menu__item">
<a href="{{link_url::288}}#next-medtech"><span>Medtech</span></a>
</div>
<div class="next-money menu__item">
<a href="{{link_url::288}}#next-money"><span>Money</span></a>
</div>
</div>
<div class="wrapper">
<div class="item next-space" data-category="next-space">Space</div>
<div class="item next-space" data-category="next-space">Space</div>
<div class="item next-space" data-category="next-space">Space</div>
<div class="item next-space" data-category="next-space">Space</div>
<div class="item next-intelligence" data-category="next-intelligence">Intelligence</div>
<div class="item next-intelligence" data-category="next-intelligence">Intelligence</div>
<div class="item next-intelligence" data-category="next-intelligence">Intelligence</div>
<div class="item next-intelligence" data-category="next-intelligence">Intelligence</div>
<div class="item next-mobility" data-category="next-mobility">Mobility</div>
<div class="item next-mobility" data-category="next-mobility">Mobility</div>
<div class="item next-security" data-category="next-security">Security</div>
<div class="item next-security" data-category="next-security">Security</div>
<div class="item next-security" data-category="next-security">Security</div>
<div class="item next-security" data-category="next-security">Security</div>
<div class="item next-mobility" data-category="next-mobility">Mobility</div>
<div class="item next-medtech" data-category="next-medtech">Medtech</div>
<div class="item next-medtech" data-category="next-medtech">Medtech</div>
<div class="item next-medtech" data-category="next-medtech">Medtech</div>
<div class="item next-medtech" data-category="next-medtech">Medtech</div>
<div class="item next-medtech" data-category="next-medtech">Medtech</div>
<div class="item next-medtech" data-category="next-medtech">Medtech</div>
<div class="item next-money" data-category="next-money">Money</div>
</div>
解决方案
您可以使用 isInViewPort 函数,通过它您可以确定 html 元素是否在屏幕上。因此,您可以突出显示侧边栏项目。
function isInViewport(element) {
const rect = element.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
将html元素传递给函数,函数将返回true或false,true在屏幕上,false不在屏幕上。如果您在用户向下滚动页面时对此进行控制,则可以突出显示正确的侧边栏项目。
也可以查看此链接: https ://www.javascripttutorial.net/dom/css/check-if-an-element-is-visible-in-the-viewport/
推荐阅读
- roku - 如何在brightscript中获得互联网速度
- python - 如何使用环境变量覆盖python配置
- java - Web 元素之间的等待时间 [Webdriverwait Selenium]
- html - 我必须设置打印布局。材料超出 A4 页
- javascript - 带 foreach 的循环插入
- kubernetes - 改变 Kubernetes 工作的形象
- amazon-s3 - 如何使用 Kafka connect s3 sink 连接器标记 S3 存储桶对象
- python - 如何选择一组行而不是单行?
- python - [错误 18] 是否有解决方法:使用 Popen 调用“pip”时跨设备链接无效?
- regex - 如何使一张纸上的列仅包含另一列中的值或所述值的组合?