基于 Vue 的兩層吸頂踩坑總結(jié)
前言
近日,在做活動(dòng)頁(yè)的過(guò)程中遇到兩層吸頂?shù)男枨螅⑶乙嫒?IE9 及以上的瀏覽器。乍一看不就是個(gè)吸頂嘛,應(yīng)該不難吧,事實(shí)證明還是踩了很多坑才出來(lái)。兼容性問(wèn)題多到吐血,我太難了。廢話不多說(shuō),先看一下兩層吸頂?shù)淖罱K實(shí)現(xiàn)效果,如下圖所示。
圖片.gif
功能點(diǎn):兩層吸頂,因?yàn)?Tabs 區(qū)域比較長(zhǎng)所以在滾動(dòng)過(guò)程中點(diǎn)擊一層 Tabs 會(huì)回彈至一層吸頂剛吸頂?shù)奈恢茫@個(gè)功能點(diǎn)和錨點(diǎn)有些類似。二層 Tabs 通過(guò) hover 切換,沒(méi)有回彈效果。
實(shí)現(xiàn)方式
本文主要通過(guò) ?VueSticky ?插件來(lái)實(shí)現(xiàn)吸頂,實(shí)現(xiàn)步驟描述如下:
安裝:
npm install vue-sticky --save引入: ?
import VueSticky from "vue-sticky"- 使用:
directives: {
'sticky': VueSticky,
},
<ELEMENT v-sticky="{ zIndex: NUMBER, stickyTop: NUMBER, disabled: [true|false]}">
<div>
CONTENT
div>
ELEMENT>
看了 ?VueSticky ?的源碼后將該插件的實(shí)現(xiàn)原理簡(jiǎn)要概括如下:
首先判斷該瀏覽器是否支持 ?position:sticky;,若支持就用 ?position:sticky; ?來(lái)實(shí)現(xiàn),若不支持就用 ?position:fixed; ?的方式實(shí)現(xiàn)
所以大家不用擔(dān)心兼容性問(wèn)題,因?yàn)槲乙呀?jīng)幫大家測(cè)試過(guò)了,IE9 及以上的瀏覽器都可以支持。
生效條件
需要注意的是,使用 v-sticky 有幾個(gè)必要條件,否則會(huì)失效:
- 父元素不能設(shè)置 ?
overflow:hidden?或者 ?overflow:auto?屬性 - 至少指定 top 、bottom 、left 、right ?4 ?個(gè)值中的一個(gè),否則只會(huì)處于相對(duì)定位
- 父元素的高度不能低于 sticky 元素的高度
- sticky 元素僅在其父元素內(nèi)生效
問(wèn)題匯總
◎ 吸頂“疊羅漢”
吸頂元素在滾動(dòng)到組件底部時(shí),在谷歌、火狐等瀏覽器中,兩層吸頂在消失過(guò)程中有重疊現(xiàn)象,具體現(xiàn)象如下圖所示:

主要原因:第一層吸頂還符合吸頂條件,第二層吸頂已經(jīng)開(kāi)始消失解決方案:給第一層吸頂元素添加 ?
minHeight ?屬性,其大小為第一層吸頂元素的高度與第二層吸頂元素的高度的和。這里有一個(gè)需要注意的點(diǎn)在于:一開(kāi)始第一層吸頂元素的高度并非兩者之和,所以這里就需要監(jiān)聽(tīng)滾動(dòng)事件,在吸頂元素距離底部的距離為兩者高度之和的位置處給第一層吸頂元素添加 ? minHeight ?屬性以下代碼塊中,sumHeight 表示兩個(gè)吸頂元素的高度和,initialHeight 表示的是第一層吸頂元素的高度
const offsetTop = document.querySelector(".xxx").offsetBottom;
if (offsetBottom <= sumHeight) {
document.querySelector(".xxx").style.minHeight = sumHeight;
} else {
document.querySelector(".xxx").style.minHeight = initialHeight;
}
◎ 吸頂“舍不得離開(kāi)”
在 IE 瀏覽器中,吸頂元素滾動(dòng)到組件底部時(shí)不消失,具體現(xiàn)象如下圖所示

position:sticky; 屬性始終存在解決方案:監(jiān)聽(tīng)滾動(dòng)事件,當(dāng)滾動(dòng)到組件底部時(shí),將 v-sticky="{ stickyTop: 0, disabled: false }" 中的 disabled 的值設(shè)為 true 即可
◎ 吸頂“難舍難分”
在 IE 瀏覽器中,兩層吸頂元素始終吸在一起

ECE1EF93-1887-495c-8F35-19552522A406.png
主要原因:第二層吸頂元素在不需要吸頂?shù)膮^(qū)域,它的 position 值也為 sticky
解決方案:監(jiān)聽(tīng)滾動(dòng)事件,在不需要吸頂?shù)膮^(qū)域設(shè)置它的 position 值為 static 即可
◎ 吸頂“變形”
同樣 DOM 結(jié)構(gòu)的吸頂元素,在 IE 瀏覽器中,吸頂會(huì)變形
查看 vue-sticky 的源碼,發(fā)現(xiàn) position:fixed; 是設(shè)置在要吸頂?shù)脑氐牡谝粋€(gè)子元素上

58BFFFDC-8353-4A35-87FC-C7848155842E.png
因此為了兼容IE需要多加一層 div 結(jié)構(gòu)
<div v-sticky="{ stickyTop: 0, disabled: false }">
<div>
content
div>
div>
注意事項(xiàng)
- 組件的監(jiān)聽(tīng)與移除
mounted() {
// handleScroll 為頁(yè)面滾動(dòng)的監(jiān)聽(tīng)回調(diào)
window.addEventListener('scroll', this.handleScroll);
},beforeDestroy() {
removeEventListener("scroll", this.handleScroll);
},同時(shí)要在
destroy回調(diào)中移除監(jiān)聽(tīng)- 在
mounted回調(diào)中加入以下代碼
優(yōu)化點(diǎn)
- 用監(jiān)聽(tīng)事件監(jiān)聽(tīng)滾動(dòng)時(shí),吸頂消失的很突兀
let supportCSSSticky = document.querySelector(".xxx").style.position === "sticky";
if (!supportCSSSticky) {
// 不支持的情況下監(jiān)聽(tīng)滾動(dòng)
}判斷瀏覽器是否支持
sticky,若支持用position:sticky;實(shí)現(xiàn),否則用position:fixed;
圖片懶加載
- 對(duì)于圖片過(guò)多的頁(yè)面,為了加速頁(yè)面的加載速度,我們需要將頁(yè)面內(nèi)未出現(xiàn)在可視區(qū)域內(nèi)的圖片先不做加載, 等到滾動(dòng)到可視區(qū)域后再去加載。這樣子對(duì)于頁(yè)面加載性能上會(huì)有很大的提升,也提高了用戶體驗(yàn),關(guān)于圖片優(yōu)化方面內(nèi)容可以閱讀我們團(tuán)隊(duì)另一篇文章?為你重新系統(tǒng)梳理下, Web 體驗(yàn)優(yōu)化中和圖有關(guān)的那些事(萬(wàn)字長(zhǎng)文)
總結(jié)
本文簡(jiǎn)單的介紹了 VueSticky ?插件的實(shí)現(xiàn)原理并分享了實(shí)戰(zhàn)過(guò)程中出現(xiàn)的問(wèn)題以及解決方案,希望對(duì)大家有所幫助。如果大家也遇到過(guò)兩層吸頂?shù)膯?wèn)題或者你還知道更好的解決方案,歡迎在評(píng)論區(qū)留下寶貴評(píng)論。
推薦閱讀
我的公眾號(hào)能帶來(lái)什么價(jià)值?(文末有送書規(guī)則,一定要看)每個(gè)前端工程師都應(yīng)該了解的圖片知識(shí)(長(zhǎng)文建議收藏)
為什么現(xiàn)在面試總是面試造火箭?
「一個(gè)有溫度的前端號(hào)」
長(zhǎng)按識(shí)別二維碼關(guān)注

點(diǎn)贊分享是對(duì)作者最大的支持!
