scrollTop,offsetTop,scrollIntoView配合實現簡單的定位功能
阿新 • • 發佈:2018-12-09
js的各種offsetXXX和scrollXXX的介紹非常多,其使用也非常廣泛,特別是在需要對頁面定位的時候,最近實現一個簡單的目錄點選定位內容及滾動螢幕定位目錄標題的小功能,完全是靠這兩個屬性實現,當然事件監聽啥的,這肯定是必要的。
直接上程式碼:
一、頁面滾動,自動定位目錄:
//滾動頁面目錄自動定位顯示 let autoActive = function(){ let html_top = document.getElementsByTagName("html")[0].scrollTop; //獲得父級捲去的高度 //標題自動定位 for (let i = 0 ;i < h3_len ; i++) { //父級捲去高度與對應文字標題距離頂部高度對比,小於說明對應標題顯示在可視口內 if (html_top <= h3_eles[i].offsetTop) { //省略獲得目錄列表中對應index的列表內容,並新增啟用樣式,刪除其他列表項啟用樣式程式碼 break; } } }; document.addEventListener("scroll",autoActive);
上面是滾動螢幕根據捲去的內容,自動定位目錄列表中相應的標題,核心就是比對父級捲去高度與相應標題距頂部的高度(此處以html為父級)如果小於,則說明當前標題可視,則改變目錄中對應的樣式即可,注意事件繫結與事件處理函式的分離,後續需要有其他操作。
二、點選目錄,定位頁面內容
//點選目錄切換函式其中變數為已經定義好的DOM節點,根據需要自行定義即可 let switchCatalog = function(e){ //點選時取消滾動事件,防止衝突 document.removeEventListener("scroll",autoActive); let index = e.target.index; //啟用切換 e.target.className += " active-catalog"; //取消其他對應列表的樣式 for (let i = 0; i< a_len;i++) { if(a_eles[i].index != index){ a_eles[i].className = ""; }; }; //滾動頁面內容 h3_eles[index].scrollIntoView({ block: 'start', behavior: 'smooth' }); //判斷是否滾動完畢,再次新增滾動事件 let temp = 0; setTimeout(function judge(){ let temp1 = document.getElementsByTagName("html")[0].scrollTop; if (temp != temp1) { //兩次滾動高度不等,則認為還沒有滾動完畢 setTimeout(judge,100); temp = temp1; //滾動高度賦值 } else{ document.addEventListener("scroll",autoActive); temp = null; //放棄引用 } },100); }; //繫結動作 document.querySelector("#catalog").addEventListener("click",switchCatalog);
這段程式碼內容比較多,總結一下:
1. 使用了scrollIntoView()代替錨點定位,並且有滾動效果,通過點選目錄列表的index值,尋找頁面內容對應相同index值的標題,滾動其到可視口內;
2. 由於滾動會觸發之前繫結的scoll事件,從而造成目錄閃動,因此需要先取消滾動監聽事件(這裡就是為啥要事件與處理邏輯相分離,如果不分離,是不能取消的,另外, 由於IE不支援scrollIntoView的滾動效果,所以就沒有這個問題,當然如果不設定動畫,也不會有此問題);
3. 當頁面滾動完畢,需要重新監聽滾動事件,否則頁面滾動,就沒有目錄定位效果了。這裡就需要判斷什麼時候滾動結束了,我這裡是利用setTimeout定時器鏈(這樣就不用clear定時器了,我比較懶),依然獲取父級的scollTop值,並進行快取,比對兩次的值,如果兩次值一致了,說明頁面停止滾動了,此時就可以加上滾動事件,否則繼續判斷。
如此兩步,利用scrollTop,offsetTop,scrollIntoView,搭配定時器和監聽器,就實現了一個雙向的定位功能。
嗯,js很強大,就怕不敢想,歡迎大神指正!不勝感激!
目錄