頁面中的錨點各位想必都「瞭如指掌」,其基於a連接「同頁面跳轉」和「id屬性標籤的歷史問題」。javascript
可能有人不知道的是:HTML中的「id」很是神奇:id屬性的元素不只能夠在js中直接使用,而沒必要先獲取;還能夠和url相關聯。
直接用id訪問是舊版本js遺留下來的特性,瀏覽器會創建window實例的id同名屬性,這是爲了兼容舊的網頁。但不要依賴這個特性,在含有特殊字符或者和window實例的其餘屬性有衝突時可能失效。css
咱們都知道,錨點應該這樣用:html
<a href="這裏寫#號+id名">去這裏</a> <div id="上面a中引用的id名">我是目的地</div>
如此即可。java
可是這裏面有兩個小問題:web
- 使用錨點後url中也會帶有href中的字符串(#號+id名)
- 由於是相似跳轉方式,因此過程很是生硬
好比有的網頁中有這樣的效果:點擊側邊欄或頂部某一個div後整個頁面滑動到相應的位置,就像這樣——
瀏覽器
之前來講用錨點確定是不現實的,因此咱們須要找到一個適合的API。dom
按照需求,即點擊某個div後對應部分的頂部要「恰好」到窗口可視區的頂部!這裏面咱們要考慮的必定是「如何算div的頂部在窗口可視區頂部」。
js提供了一個有趣的API能夠完成咱們的需求 —— getBoundingClient()
,它至關因而封裝了client API並把它應用在普通元素上,經過它咱們能獲得此元素距離可視區頂部、左邊的距離,好比:
svg
而且根據上一篇文章(點擊閱讀文章)中所提,document下的scrollTop API可爲咱們提供文檔流(頁面總體區域)向上滾動了多少距離。函數
筆者在這裏再次提醒各位要區分js中inner系、page系、client系、offset系、outer系、screen系…事件,他們的含義各不相同。好比常說的offsetTop/Left,是距離上一級父元素的上/左邊距,一般用
if(dom.parentElement)
作累加求的是「距離文檔流頂部的距離」,就不適用於此處。網站
將兩者結合起來使用,就能夠達到:若想要展現的區域在下方,就讓文檔流不斷向上滾動,直到此區域滑動到可視區頂端;反之若想要展現的區域已經滑過,就讓文檔流不斷向下滾動。
/** leftBtn:側邊欄中全部負責頁面滾動的div,都有一個class屬性爲left-btn i:left-btn所屬div的下標(第幾個) .mao1/2/3:頁面中負責「滑到頂部」的div,通常是某一個區域的小標題 */ let leftBtn=document.querySelectorAll(".left-btn") function gotoTop(i,top){ var timer=null; leftBtn[i].onclick=function(){ let scrollTop=document.body.scrollTop ||document.documentElement.scrollTop || window.pageYOffset // 若目標位置在當前位置上方 if(scrollTop>top){ clearInterval(timer) timer=null; timer=setInterval(function(){ scrollTop=scrollTop-90<top?top:scrollTop-90; document.body.scrollTop=document.documentElement.scrollTop=window.pageYOffset=scrollTop if(scrollTop<=top){ clearInterval(timer); timer=null; } },50) // 目標位置在當前位置下方 }else if(scrollTop<top){ clearInterval(timer) timer=null; timer=setInterval(function(){ scrollTop=scrollTop+90>top?top:scrollTop+90; document.body.scrollTop=document.documentElement.scrollTop=window.pageYOffset=scrollTop if(scrollTop>=top){ clearInterval(timer); timer=null; } },50) } } }
使用如:
let one_top=document.querySelector(".mao1").getBoundingClientRect().top let two_top=document.querySelector(".mao2").getBoundingClientRect().top let thr_top=document.querySelector(".mao3").getBoundingClientRect().top gotoTop(0,one_top); gotoTop(1,two_top); gotoTop(2,thr_top);
這樣就能達到上面展現的效果了。
這裏面須要注意的是:
setInterval()
定時器的清除!
若是上方代碼去掉第1四、1五、2六、27行,則頁面滾動行爲會發生錯誤。看上去彷佛是clearInterval
失效了!其實這個問題自己是因爲js定時器特性產生的。clearInterval
是根據定時器自己的標識來進行清除的,若是在期間生成了新的interval,並覆蓋timer標識對象,舊有的timer定時器對象並不會被中止和清除,並且標識也會丟失致使再也沒法被清除,因此寫定時器時必定要注意。建議在調用某個定時器任務的函數的時候,必定一開始就把以前的定時器先清除!
這個問題到這裏彷佛很好的解決了。可是上面代碼畢竟仍是太長了,並且裏面要進行嚴格的判斷以決定開始和結束(定時器的增長和刪除),彷佛稍有不妥。
不過別急,js更新了另外一個神器 —— scrollIntoView()
,原先這個API的做用就是讓指定的div的頂部跳到窗口可視區頂部(從效果上看相似錨點),可是更新後增長了配置參數:
dom.scrollIntoView({ behavior:"smooth" // ! })
這個參數的做用就是「平滑滾動」!不過因爲新因此兼容性目前還不算很好,可是也無妨,畢竟它本來的做用還在,能夠把新特性當作「只對少數用戶更新的體驗」。
說完了錨點效果,來講說頁面中廣泛存在的「回到頂部」。
一樣的,以前筆者作社團官網的時候就採用了控制scrollTop
不斷--
的方法。如今看來太麻煩了,用上面提到的 scrollIntoView()
API就可完成:
目前大部分官網/網站都採用了在頁面頂部(左上角)放一張logo的形式。針對使用這種形式的網站,如果logo所在div不是採用 position:fixed;
的方式固定在頂部的話,咱們能夠將img外面包裹一層a標籤,而後就能夠在「回到頂部」按鈕的事件中這麼寫:
document.links[0].scrollIntoView({ behavior:"smooth" }) //或者 直接定位圖片 document.images[0].scrollIntoView({ behavior:"smooth"})
這裏還要提到js中後來新加入的兩個原生API:scrollTo
(滾動到哪裏) 和 scrollBy
(滾動多少距離)。這裏爲啥提到這倆?由於scrillTo這個API能夠在ie上使用!它被支持在window上,好比:回到頂部window.scrollTo(0,0);
但這裏也只是提一句讓各位有個印象,非要用在本文所提場景下則大可沒必要。
說到這,前幾天驚奇的發現CSS中多了一個控制頁面滾動的屬性!(去年年末開始支持的)原平生滑滾動定位 —— scroll-behavior
,它有兩個值:
- auto:初始值。啥也沒有。
- smooth:做用在滾動容器元素上,可讓容器內的滾動變得平滑。
好比在筆者文章中屢次出現的tab框切換,若是你只設置了父容器的 overflow:hidden;
而子元素採用了相對父元素定位的方式展現(display、opacity、visibility都不行,由於他們本質上都不是經過位置移動展現元素的),那麼就能夠在父容器上加上一行:scroll-behavior: smooth;
效果賊好,生動了許多!
還有上面說的「回到頂部」(和「錨點」),若是不想用js實現並且又不抗拒url後面的小小「#」的話,其實你能夠這麼實現:
/** css樣式 */ html, body { scroll-behavior:smooth; }
<a href="#">返回頂部</a>
包括上面的「錨點效果」也能夠這麼來~
perfect!
元旦將至,提早祝各位元旦快樂,溜了溜了~
本文同步分享在 博客「行舟客」(CSDN)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。