1、之前有写的vue的,方法跟这个大致相同,有兴趣的可以看看vue 实现类似于锚点滑动 或者点击不同的tab时添加下划线并滑动到对应的盒子,手动滑动下划线也随位置变动-CSDN博客
2、这里有两种方式,但是第一种方式存在弊端,就是当我们顶部的导航栏是固定定位,滑动到对应的视口位置,有一部分内容被压住了,就是滑过了,这个时候我们就要用第二种方式,第二种方式可以灵活的根据导航栏的高度去调节,以便滑动到对应的盒子可以完整展现出来
3、内容跟样式部分是通用的,只有JS部分有区别
4、html 结构 ,如果对应你帮助,记得点赞
<ul id="nav-list" class="tabsul">
<li class="liTem active" data-target="section1">首页</li>
<li class="liTem" data-target="section2">服务内容</li>
<li class="liTem" data-target="section3">业务案例</li>
<li class="liTem" data-target="section4">关于我们</li>
<li class="liTem" data-target="section5">联系方式</li>
</ul>
<div class="section1 section" id="section1"></div>
<div class="section2 section" id="section2"></div>
<div class="section3 section" id="section3"></div>
5、css部分
.tabsul {
display: flex;
line-height: 30px;
justify-content: space-between;
list-style-type: none;
}
.liTem {
margin: 50px;
padding: 0 0px 5px 0px;
box-sizing: border-box;
height: 35px;
text-align: center;
font-size: 16px;
font-weight: 500;
margin: 0 20px;
cursor: pointer;
list-style-type: none;
position: relative;
}
.liTem.active::after {
content: "";
position: absolute;
width: 100%;
height: 2px;
bottom: 0;
left: 0;
border-bottom: 3px #ff8000 solid;
}
.section1 {
width: 100%;
height: 600px;
color: #fff;
font-size: 30px;
font-weight: 600;
display: flex;
}
.section2 {
width: 100%;
height: 400px;
color: #fff;
font-size: 30px;
font-weight: 600;
display: flex;
}
.section3 {
width: 100%;
height: 700px;
color: #fff;
font-size: 30px;
font-weight: 600;
display: flex;
}
6、JS部分,这是第一种方法
document.addEventListener("DOMContentLoaded", function () {
const navList = document.getElementById('nav-list');
const sections = document.querySelectorAll('.section');
let timeout;
let activeElement = document.querySelector('.liTem');
activeElement.classList.add('active');
navList.addEventListener('click', function (e) {
if (e.target.classList.contains('liTem')) {
e.preventDefault(); // 阻止默认行为
const targetId = e.target.getAttribute('data-target');
const targetElement = document.getElementById(targetId);
clearTimeout(timeout);
if (activeElement !== e.target) {
// activeElement.classList.remove('active');
// e.target.classList.add('active');
e.preventDefault(); // 阻止默认行为
activeElement = e.target;
timeout = setTimeout(() => {
targetElement.scrollIntoView({
behavior: 'smooth',
block: 'start',
})
}, 100);
}
}
});
window.addEventListener('scroll', function () {
let fromTop = window.scrollY;
sections.forEach(function (section) {
if (section.offsetTop <= fromTop && section.offsetTop + section.offsetHeight > fromTop) {
document.querySelectorAll('.liTem').forEach(item => item.classList.remove('active'));
document.querySelector(`[data-target=${section.id}]`).classList.add('active');
}
});
});
});
第二种方法
const tabItems = document.querySelectorAll('.liTem');
const sections = document.querySelectorAll('.section');
tabItems.forEach(item => {
item.addEventListener('click', function() {
const targetId = this.getAttribute('data-target');
const targetSection = document.getElementById(targetId);
const offset = 100; // 滑动偏移量 这个就是可以改你对应的导航栏的高度,就是被遮住的部分
const targetPosition = targetSection.offsetTop - offset;
window.scrollTo({
top: targetPosition,
behavior: 'smooth'
});
});
});
window.addEventListener('scroll', function() {
let fromTop = window.scrollY;
sections.forEach(section => {
if (fromTop >= section.offsetTop - 100) {
let targetId = section.getAttribute('id');
// 移除所有 tab 的 active 类
tabItems.forEach(tabsul => tabsul.classList.remove('active'));
// 给对应的 tab 添加 active 类
document.querySelector(`[data-target="${targetId}"]`).classList.add('active');
}
});
// 实时计算当前页面位置,确定应该添加下划线的 liTem
let currentPosition = window.scrollY + 100;
tabItems.forEach(tabsul => {
let targetId = tabsul.getAttribute('data-target');
let targetSection = document.getElementById(targetId);
if (currentPosition >= targetSection.offsetTop && currentPosition < targetSection.offsetTop + targetSection.offsetHeight) {
tabItems.forEach(tabsul => tabsul.classList.remove('active'));
tabsul.classList.add('active');
}
});
});