【前端三分钟】锚点自动跟随滚动定位

在这里插入图片描述

最近看到写 “锚点自动跟随滚动定位”的方法,大都是基于JQ,或者是第三方。
所以,进行给出使用原生JS的写法。
什么都不说了,直接上代码(使用模块模式方式):

<!DOCTYPE html>
<html>
<head>
	<title></title>
	<style>
        div.section_maodian {height: 500px;width: 100%;}
        ul,li {list-style: none;}
        ul {position: fixed; right:10px;width: 100px;}
        li {height: 20px;background: burlywood;padding: 10px;cursor: pointer;}
        li.active {background-color: brown;}
        li.active {color: #fff};
    </style>
</head>
<body>
	<div class="section_maodian">秒杀专区</div>
    <div class="section_maodian">买一赠一</div>
    <div class="section_maodian">品牌齐聚</div>
    <script>
	const ScrollAnchorModule = function() {
		let scrollH = document.documentElement.scrollTop||document.body.scrollTop;
		//scroll更新
		const updateNav = (secItems,navItems) => {
			if(getScrollTop()===0)
				navon(0,navItems);
			if(getScrollTop()+getWindowHeight()===getScrollHeight())
				navon(secItems.length-1,navItems);
			else {
				secItems.forEach((item,index)=>{
					if(getScrollTop()>=item.offsetTop){
						navon(index,navItems);
					}
				});
			}
		}
		//定位
		const toScroll = (index,secItems) => {
			//计算位置
			let scrollY = secItems[index].offsetTop;
			window.scrollTo(0,scrollY);
		}
		//当前锚点
		const navon = (index,navItems) => {
			navItems.forEach((item)=>{
				item.classList = "";
			});
			navItems[index].classList = "active";
		}
		//防抖
		const debounce = (fn,wait) => {
	        let timeout = null;
	        return function() {
	            if(timeout!==null) clearTimeout(timeout);
	            timeout = setTimeout(fn,wait);
	        }
	        
	    }
	    //节流
		const throttle = (fn,delay) => {
	        let prev = Date.now();//记录上一次触发回调的时间
	        return function() {
	            let context = this;//保留调用时的this上下文
	            let args = arugments;//保留调用时传入的参数
	            let now = Date.now();//记录本次触发回调的时间
	            if(now-prev >=delay) {//判断上次触发回调的时间和本次触发回调的时间差十分小于时间间隔的阈值
	                fn.apply(context,args);//大于设定的阈值,则执行回调
	                prev = Date.now();
	            }
	        }
	    }
	    //滚动条在Y轴上的滚动距离
	    const getScrollTop = () => {
	    	let scrollTop = 0, bodyScrollTop = 0, documentScrollTop = 0;
	      if(document.body){
	        bodyScrollTop = document.body.scrollTop;
	      }
	      if(document.documentElement){
	        documentScrollTop = document.documentElement.scrollTop;
	      }
	      scrollTop = (bodyScrollTop - documentScrollTop > 0) ? bodyScrollTop : documentScrollTop;
	      return scrollTop;
	    }
	    //文档的总高度
	    const getScrollHeight = () =>{
	    	let scrollHeight = 0, bodyScrollHeight = 0, documentScrollHeight = 0;
	      if(document.body){
	        bodyScrollHeight = document.body.scrollHeight;
	      }
	      if(document.documentElement){
	        documentScrollHeight = document.documentElement.scrollHeight;
	      }
	      scrollHeight = (bodyScrollHeight - documentScrollHeight > 0) ? bodyScrollHeight : documentScrollHeight;
	      return scrollHeight;
	    }
	    //浏览器视口(窗口)的高度
	    const getWindowHeight = () =>{
	    	let windowHeight = 0;
	      if(document.compatMode == "CSS1Compat"){
	        windowHeight = document.documentElement.clientHeight;
	      }else{
	        windowHeight = document.body.clientHeight;
	      }
	      return windowHeight;
	    }
		return {//模块返回接口
			init: (options) => {
				let html = `<ul class="sideMaodian">`+options.navMenu.map((item,index)=>{
				return `<li class="nav_maodian ">${item}</li>`;
				}).join('')+`</ul>`;
				document.body.insertAdjacentHTML('afterbegin',html);

				let navItems = document.querySelectorAll(options.navClass);
				let secItems = document.querySelectorAll(options.secClass);
				let sideMaodian = document.querySelector('.sideMaodian');
				if(scrollH===0)
					navon(0,navItems);
				
				//利用事件冒泡机制,在点击的li元素的祖先元素ul标签上注册click事件
				sideMaodian.addEventListener('click',event=>{
					let item = event.target;
					let lists = Array.from(sideMaodian.querySelectorAll('li'));
					let index = lists.indexOf(item); //li 索引
					if(event.target.tagName.toLowerCase() === 'li'){
						navon(index,navItems);
						toScroll(index,secItems);
					}
				},false);
				//注册scroll事件
				window.addEventListener('scroll',event=>{
					event.stopPropagation();
					debounce(updateNav(secItems,navItems),1000);
				},false);
				
			}
		}

	}();
	var options = {
		navClass:'.nav_maodian',
		secClass:'.section_maodian',
		navMenu:['秒杀专区','买一赠一','品牌齐聚']
	}
	ScrollAnchorModule.init(options);
    </script>
</body>
</html>

参考 :

防抖与节流

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程轨迹_

期望和你分享一杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值