【前端三分鐘】錨點自動跟隨滾動定位

最近看到寫 “錨點自動跟隨滾動定位”的方法,大都是基於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>

參考 :

防抖與節流

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章