聊聊頁面中的錨點效果和回到頂部

頁面中的錨點各位想必都「瞭如指掌」,其基於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

  1. 使用錨點後url中也會帶有href中的字符串(#號+id名)
  2. 由於是相似跳轉方式,因此過程很是生硬

好比有的網頁中有這樣的效果:點擊側邊欄或頂部某一個div後整個頁面滑動到相應的位置,就像這樣——
js點擊滾動對應區域瀏覽器

之前來講用錨點確定是不現實的,因此咱們須要找到一個適合的API。dom

按照需求,即點擊某個div後對應部分的頂部要「恰好」到窗口可視區的頂部!這裏面咱們要考慮的必定是「如何算div的頂部在窗口可視區頂部」。
js提供了一個有趣的API能夠完成咱們的需求 —— getBoundingClient() ,它至關因而封裝了client API並把它應用在普通元素上,經過它咱們能獲得此元素距離可視區頂部、左邊的距離,好比:
getBoundingClient-APIsvg

而且根據上一篇文章(點擊閱讀文章)中所提,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"})

scrollIntoView

這裏還要提到js中後來新加入的兩個原生API:scrollTo(滾動到哪裏) 和 scrollBy(滾動多少距離)。這裏爲啥提到這倆?由於scrillTo這個API能夠在ie上使用!它被支持在window上,好比:回到頂部window.scrollTo(0,0);
但這裏也只是提一句讓各位有個印象,非要用在本文所提場景下則大可沒必要。


說到這,前幾天驚奇的發現CSS中多了一個控制頁面滾動的屬性!(去年年末開始支持的)原平生滑滾動定位 —— scroll-behavior ,它有兩個值:

  1. auto:初始值。啥也沒有。
  2. 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源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索