JS原生实现浏览器滚动条滚动侧边栏高亮响应
2023-12-13 09:41:03
目录
2、定义一个rectContent数组,然后循环allContents调用getClientRects()[0]获取每个link-content元素与浏览器视口的关系
演示
需求
左侧侧边栏link1、link2...所对应右侧内容link1-content、link2-content...,当鼠标点击link的时候,自动滚动到对应的content。手动拖动滚动条,左侧link进行高亮响应,当link2-content出现在视口的时候,左侧link2高亮,当link2-content和link3-content同时出现在视口的时候,左侧link2高亮(谁接近视口顶部,对应的link高亮)。
代码
css
* {
padding: 0;
margin: 0;
list-style: none;
}
.header {
height: 200px;
background-color: aqua;
}
.main {
padding: 30px 0;
display: flex;
max-width: 1400px;
margin: 0 auto;
gap: 30px;
}
.main .sidebar {
position: sticky;
top: 0;
width: 300px;
align-self: start;
}
.main .content {
display: flex;
flex: 1;
flex-direction: column;
gap: 30px;
}
.main .content .content-item{
background-color: aqua;
height: 400px;
}
.main .sidebar ul li{
padding: 20px 10px;
background-color: aqua;
}
.main .sidebar ul li .active{
color: red;
}
.footer {
height: 200px;
background-color: aqua;
}
html
<body>
<section class="header"></section>
<section class="main">
<div class="sidebar">
<ul>
<li><a class="active" href="#content-item1">link1</a></li>
<li><a href="#content-item2">link2</a></li> // 设置锚点所对应的content的id
<li><a href="#content-item3">link3</a></li>
<li><a href="#content-item4">link4</a></li>
<li><a href="#content-item5">link5</a></li>
<li><a href="#content-item6">link6</a></li>
</ul>
</div>
<div class="content">
<div id="content-item1" class="content-item">link1-content</div>
<div id="content-item2" class="content-item">link2-content</div>
<div id="content-item3" class="content-item">link3-content</div>
<div id="content-item4" class="content-item">link4-content</div>
<div id="content-item5" class="content-item">link5-content</div>
<div id="content-item6" class="content-item">link6-content</div>
</div>
</section>
<section class="footer"></section>
</body>
script
const allLinks = document.querySelectorAll("a:link");
allLinks.forEach(function (link) {
link.addEventListener("click", function (e) {
e.preventDefault();
const href = link.getAttribute("href");
if ( href.startsWith("#")) {
const sectionEl = document.querySelector(href);
link_content.scrollIntoView({ behavior: "smooth" });
}
});
});
设置link的href和link-content的id所对应,调用scrollIntoView({ behavior: "smooth" })自动滚动到对应的位置。
const handleScroll = () => {
const allContents = document.querySelectorAll(".content-item");
const rectContent = [];
allContents.forEach((ele) => {
const eleRect = ele.getClientRects()[0];
if (
(eleRect.top >= 0 && window.innerHeight - eleRect.top >= eleRect.height) ||
(eleRect.top < 0 && window.innerHeight <=
eleRect.height - Math.abs(eleRect.top)) ||
eleRect.top >= 0
) {
rectContent.push(ele);
}
});
let linkId
if (rectContent[0]) linkId = rectContent[0].id
allLinks.forEach(link => link.classList.remove('active'))
const linkDom = document.querySelector(`a[href="#${linkId}"]`)
linkDom.classList.add('active')
}
window.addEventListener("scroll", function() {
throttle(handleScroll, 100)();
});
window.addEventListener('mouseup', function() {
throttle(handleScroll, 100)();
});
代码解释
浏览器滚动,每次滚动触发scroll回调
1、获取所有link-content
2、定义一个rectContent数组,然后循环allContents调用getClientRects()[0]获取每个link-content元素与浏览器视口的关系
3、为数组追加link-content,用于设置侧边栏高亮
情况1
?link-content1和link-content2都完全出现在视口中,谁接近视口顶部,对应的link高亮
情况2
如果情况1没有命中,则判断是否有元素占满整个屏幕,link-content(link-content2)完全占满整个视口
情况3
都没有完全出现在视口或者完全沾满视口,则取出现在第一个link-content与视口关系top > 0的值
4、设置高亮
let linkId
if (rectContent[0]) linkId = rectContent[0].id
allLinks.forEach(link => link.classList.remove('active'))
const linkDom = document.querySelector(`a[href="#${linkId}"]`)
linkDom.classList.add('active')
找到存储在数组的第一项link-content,获取id,根据id获取对应的侧边栏link,清空之前设置的link的类active,为对应的link添加类active。
5、添加节流,减少触发回调的频率
const throttle = (fn, delay) => {
let lastExecuted = 0;
return function() {
const now = Date.now();
if (now - lastExecuted > delay) {
fn();
lastExecuted = now;
}
}
}
window.addEventListener("scroll", function() {
throttle(handleScroll, 100)();
});
window.addEventListener('mouseup', function() {
throttle(handleScroll, 100)();
});
文章来源:https://blog.csdn.net/SupperSA/article/details/134880239
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!