簡單來說,我有一個側邊欄,上面有一個類別列表。在正文中,我列出了許多卡片,每張卡片對應于側邊欄列表中的一個類別。
目標:當我滾動頁面時,我希望側邊欄中正確的類別被高亮顯示。
嘗試:我已經在這個代碼欄中嘗試了一段時間,但不知何故,我似乎不能得到它。
這是我的代碼:
/* 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)
);
}
如果您仍然有這個問題,有一個現代的方法可以實現這一點——使用交叉點觀察器API。
他們的文件說:
在過去,實現交集檢測涉及事件處理程序和循環調用Element.getBoundingClientRect()等方法,以便為每個受影響的元素構建所需的信息。因為所有這些代碼都在主線程上運行,所以即使其中一個也會導致性能問題。