实现效果:
html代码:
<div class="sidenav"><ul class="nav-text progressbar"><!-- data-target的值对应要跳转的模块的id --><li data-target="module1"><div class="text">锚点名称</div></li><li data-target="module2"><div class="text">锚点名称</div></li><li data-target="module3"><div class="text">锚点名称</div></li><li data-target="module4"><div class="text">锚点名称</div></li></ul>
</div>
给要跳转的dom元素id赋值即可。
css:
/* 侧边锚点跳转 */
.sidenav {z-index: 40;left: 1%;bottom: 15%;min-height: 55px;position: fixed;/* width: 140px; */background: #ffffff;box-shadow: 0px 0px 35px 0px rgba(106, 76, 248, 0.16);border-radius: 8px;padding: 25px 22px 0px 16px;
}.progressbar li {list-style-type: none;/* float: left; width: 33.33%; */position: relative;text-align: center;font-size: 16px;align-items: center;display: flex;height: 42px;max-width: 102px;margin-bottom: 25px;
}.progressbar .text {-webkit-box-orient: vertical;display: -webkit-box;/* width: 64px; */width: 80px;text-align: left;-webkit-line-clamp: 2;overflow: hidden;text-overflow: ellipsis;
color: #333333;
cursor: pointer;
}.progressbar li:before {content: "";text-align: center;width: 12px;height: 12px;
background: #999999;border-radius: 50%;margin-right: 10px;
}.progressbar li:after {/* 伪元素实现li圆点垂直相连的线*/top: -13px;transform: translate(-50%, 0) rotate(90deg);content: "";position: absolute;width: 66%;height: 1px;background: #999999;;left: 6px;z-index: -1;
}.progressbar li:first-child:after {content: none;
}
js:
// 避免点击事件触发时,触发滚动事件增加active类的函数var isProgressBarClick = false;// 获取悬浮窗的ul元素const moduleList = document.querySelector('.progressbar');var timeoutId = null;// 滚动到对应模块并添加active类的点击事件处理函数function scrollToModule(event){isProgressBarClick = true;var aim = event.target;if(event.target.className === 'text'){aim = event.target.parentNode}const targetModuleId = aim.getAttribute('data-target');const targetModule = document.getElementById(targetModuleId);if (targetModule) {// 使用平滑滚动实现滚动效果targetModule.scrollIntoView({ behavior: 'smooth' });// 移除之前被添加的active类const activeItem = document.querySelector('.progressbar li.active');if (activeItem) {activeItem.classList.remove('active');}// 为当前点击的列表项添加active类aim.classList.add('active');}// 等待锚点跳转完成后再重置标志变量clearTimeout(timeoutId);timeoutId = setTimeout(function() {isProgressBarClick = false;}, 1000);}$('.progressbar li').click(scrollToModule)$('.progressbar li .text').click(scrollToModule)// 监听页面滚动事件window.addEventListener('scroll', handleScroll);function handleScroll() {if(!isProgressBarClick){// 获取页面滚动的垂直位置const scrollPosition = window.scrollY;// 遍历模块元素,找到当前可见的模块var activeModuleId = null;var moduleElements = document.querySelectorAll('.module_list>div')for (const moduleElement of moduleElements) {// 用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置const { top, bottom } = moduleElement.getBoundingClientRect();// 判断模块是否在视口内(至少一半在视口内)if (top <= window.innerHeight / 2 && bottom >= window.innerHeight / 2) {activeModuleId = moduleElement.id;break;}}// 添加active类if (activeModuleId) {// 移除之前被添加的active类const activeItem = document.querySelector('.progressbar li.active');if (activeItem) {activeItem.classList.remove('active');}// 为当前可见的模块对应的列表项添加active类const activeListItem = document.querySelector(`.progressbar li[data-target="${activeModuleId}"]`);if (activeListItem) {activeListItem.classList.add('active');}}}}// 初始加载时触发一次滚动事件handleScroll();