Vue開發——實現吸頂效果

由於項目需求,最近開始轉到微信公衆號開發,接觸到了Vue框架,這個效果的實現雖然說是基於Vue框架下實現的,可是一樣也能夠借鑑到其餘地方,原理都是同樣的。css

進入正題,先看下效果圖:

吸頂效果
其實js作這個效果仍是挺簡單的,由於在css中咱們能夠設置一個元素的position: fixed;,這樣它就能夠固定在那裏,這樣無論頁面怎麼滾動,它的位置都不受影響,因此咱們的思路就是在合適的時機把要吸頂的頭部元素的position屬性設置爲fixed就能夠了。可是這個合適的時機是何時呢,這就須要咱們計算了,咱們須要監聽頁面的滾動狀態,當頁面滾動到要吸頂元素所處的位置的時候就是咱們設置它固定的時候,因此就須要咱們:ios

1.監聽頁面的滾動狀態:

在mounted回調中加入如下代碼:瀏覽器

mounted() {
  // handleScroll爲頁面滾動的監聽回調
  window.addEventListener('scroll', this.handleScroll);
 },

同時在destroyed回調中移除監聽:微信

destroyed(){
  window.removeEventListener('scroll', this.handleScroll);
},

2.計算吸頂元素到頁面頂部的距離:

計算出來這個距離以後就能夠肯定固定吸頂元素的時機了,若是你的吸頂元素上面的元素的高度是固定的話,那就簡單了,直接在handleScroll方法中進行判斷就能夠了,能夠直接跳到第三步了,若是是動態的,那就須要咱們在接口請求完數據,dom元素渲染完以後進行動態計算了,Vue中有一個很好用的方法,能夠很方便的監聽dom渲染完成:框架

// 監聽dom渲染完成
this.$nextTick(function(){
  // 這裏fixedHeaderRoot是吸頂元素的ID
  let header = document.getElementById("fixedHeaderRoot");
  // 這裏要獲得top的距離和元素自身的高度
  this.offsetTop = header.offsetTop;
  this.offsetHeight = header.offsetHeight;
  console.log("offsetTop:" + this.offsetTop + "," + this.offsetHeight);
});

3.判斷頁面滾動距離:

handleScroll(){
  // 獲得頁面滾動的距離
  let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
  // 判斷頁面滾動的距離是否大於吸頂元素的位置
  this.headerFixed = scrollTop > (this.offsetTop - this.offsetHeight * 2);
},

ps:這裏理論上其實應該是scrollTop > (this.offsetTop - this.offsetHeight),可是不知道爲啥我這裏作出來後滾動到吸頂元素位置的時候scrollTop仍是比this.offsetTop - this.offsetHeight的值小,因此這裏*2,這樣得出來的值纔剛恰好,若是有知道的朋友能夠幫忙解惑一下。dom

上面咱們獲得了一個headerFixed的boolean屬性值,接下來咱們只須要根據它的值來設置吸頂元素的position: fixed;屬性就能夠了。
咱們能夠寫一個css樣式:佈局

.isFixed{
  position: fixed;
  top: px2rem(110);
  left: px2rem(20);
  right: px2rem(20);
}

而後Vue能夠在dom元素裏這樣動態設置class,很是方便:測試

<div id="fixedHeaderRoot">
  <div id="knowPointHeader" class="knowPointHeader" :class="headerFixed?'isFixed':''">
    <div><span>知識模塊</span></div>
    <div><span>知識點</span></div>
    <div><span>能力要求</span></div>
  </div>
</div>

其實到這裏這個效果已經實現完成了,不過我在測試過程當中發現,由於ios手機頁面滾動到底部的時候,還能夠上拉,有一個橡皮筋效果,這個效果會致使一個咱們頁面的一個Bug,由於它的這種橡皮筋效果也會觸發頁面滾動的監聽,當數據不少的時候其實看不出來,只有當數據恰好佔滿屏幕的時候,這個時候你再繼續往上滑動屏幕,就會觸發頁面的滾動監聽,這個時候handleScroll方法中計算出來的值scrollTop是大於吸頂元素top的距離,因此吸頂元素會被設置爲固定屬性,你們知道一個元素一旦被設置爲position: fixed;,那麼它就會相對於瀏覽器窗口進行定位,這樣咱們下面的內容就會往上頂,這樣的話scrollTop的值又小於了吸頂元素top的距離,這樣headerFixed屬性又爲false,position: fixed;屬性又沒有了,這樣它就又相對與它本來的父元素進行定位,這樣就成了一個循環,你會發現頁面會上下跳到,這樣是確定不行的,因此我下面又針對這個問題進行了一個優化,固然這個方案感受不是特別完美,不過確實能夠解決這個問題。

經過上面的分析咱們能夠得知形成這個問題的緣由是由於咱們把設置了元素的position: fixed;屬性,使得下面的內容往上頂,因此要想解決這個問題,那咱們就不固定這個元素,可是這樣的話就達不到吸頂的效果了,因此咱們須要再加一個和吸頂元素如出一轍的元素,它一直就是固定狀態:

<div id="fixedHeaderRootReal">
  <div class="knowPointHeader isFixed" v-show="headerFixed">
    <div><span>知識模塊</span></div>
    <div><span>知識點</span></div>
    <div><span>能力要求</span></div>
  </div>
</div>

這個元素默認是隱藏的,只有當頁面滾動的距離達到了它的位置的時候咱們才讓它顯示,因爲它是固定狀態,因此它的隱藏顯示並不會對頁面產生影響,這樣下面的內容就不會往上頂了,就能夠解決ios手機上拉頁面橡皮筋效果的Bug了,固然這種方式有些取巧,可是暫時沒有更好的解決方案了,若是你們有更好的解決方案,歡迎在下面評論。最後給你們看一下個人頁面佈局:

<div v-show="kpointListShow" class="knowPointList">
      <div id="fixedHeaderRoot">
        <div id="knowPointHeader" class="knowPointHeader">
          <div><span>知識模塊</span></div>
          <div><span>知識點</span></div>
          <div><span>能力要求</span></div>
        </div>
      </div>
      <div id="fixedHeaderRootReal">
        <div class="knowPointHeader isFixed" v-show="headerFixed">
          <div><span>知識模塊</span></div>
          <div><span>知識點</span></div>
          <div><span>能力要求</span></div>
        </div>
      </div>
      <div class="knowPointItem" v-for="(kpointItem,index) in rows.kpointList" :key="index">
        <div><span>{{kpointItem.knowModule}}</span></div>
        <div><span>{{kpointItem.knowPoint}}</span></div>
        <div><span>{{kpointItem.abilityRequire}}</span></div>
      </div>
</div>

參考優化

喜歡的麻煩動動小手點個贊來支持我,有不對的地方歡迎你們指正,有什麼問題也能夠在下方留言,我看到後會第一時間回覆!謝謝您來看這篇文章!🌹🌹🌹

相關文章
相關標籤/搜索