JS異步觀察目標元素方式完成分頁加載

介紹

平時我們處理分頁加載時,往往是通過滾動條判斷是否到瞭容器底部再執行的加載任務的,這樣有一個問題就是,不管滾動條是否劃到底部位置,它都會運行計算這個函數。

那麼,如果能判斷底部的加載區域出現後再去執行加載,不用再做滾動條計算瞭,這樣豈不美哉。本期將以異步觀察目標元素的新方式去完成分頁加載業務。

代碼

<div id="app" @vue:mounted="mounted" :class="{'active':active}">
  <ul>
    <li v-for="item in num"><span>{{item}}</span>
      <p></p>
    </li>'
    <div class="loading">
      <div ref="loading" v-show="!isLoading"></div>
      loading..
    </div>
  </ul>
</div>
#app{
  display: none;
  &.active{
    display: block;
  }
}
ul{
  width: 100%;
  li{
    width: 100%;
    height: 10vh;
    display: flex;
    align-items: center;
    justify-content: start;
    box-sizing: border-box;
    padding: 0 3%;
    position: relative;
    border-bottom: 1px solid #efefef;
    font-size: 14px;
    font-family: fantasy, Courier, monospace;
    span{
      display: inline-block;
      min-width: 30px;
      text-align: center;
    }
    p{
      flex: 1;
      height: 4vh;
      background-color: #e2e2e2;
      margin-left: 3%;
    }
  }
}
.loading{
  font-family: fantasy, Courier, monospace;
  display: flex;
  height: 15vh;
  align-items: center;
  justify-content: center;
  animation: loading 1s linear infinite;
}
@keyframes loading{
  0%,100%{
    opacity: 1;
  }
  50%{
    opacity:0;
  }
}
import { createApp } from 'https://unpkg.com/petite-vue?module'
createApp({
  num: 0,
  page:1,
  active:false,
  observer:null,
  isLoading:false,
  mounted() {
      this.active = true;
      this.loading = this.$refs.loading;
      this.observer= new IntersectionObserver(()=>{
         this.addNum();
      },{
        root:window.document,
        rootMargin:"0px 0px 0px 0px",
        threshold:0
      })
      this.observer.observe(this.loading)
      // this.observer.unobserve(this.loading)
  },
  addNum(){
    if(this.isLoading) return;
    this.isLoading = true;
    console.log(`loading,page:${this.page}`)
    setTimeout(()=>{ 
      this.num += 20;
      this.page ++;
      this.$nextTick(()=>{
          this.isLoading = false;
      })
    },1000)
  }
}).mount()

演示

正文

監聽元素

IntersectionObserver() 對不少小夥伴來說可能是一個比較生疏的構造器,你可以傳入監聽區域,以及監聽後的回調函數,然後它會創建並返回一個 IntersectionObserver 對象,而這個對象可以來完成監聽某個目標元素是否與該監聽區域發生交叉,每次達到檢查閾值後都會觸發剛才傳入的回調函數。

// 獲取監聽目標
this.loading = this.$refs.loading;
// 用構造器創建監聽區域對象
this.observer= new IntersectionObserver(()=>{
    this.addNum();
},{
    root:window.document, // 監聽區域,默認為整個可視窗體
    rootMargin:"0px 0px 0px 0px", // 類似margin,為邊界的偏移量用於判定范圍是否滿足計算需要,默認0px 0px 0px 0px
    threshold:0  // 閾值(0-1),表示交叉區域的比例值,默認為0
})
// 
this.observer.observe(this.loading)

根據以上代碼就可以在業務中,判斷元素是否出現在,隻要達到閾值就會觸發回調,在這個回調函數中你可以去完成加載列表等操作,從而代替頻繁用計算滾動條的位置距離的困擾。

反復交叉

或許你在嘗試使用異步觀察目標元素的這個寫法時,會發現一個嚴重的問題,就是可能本想加載一次的任務突然出現兩次請求。這又是為什麼呢?

其實就是因為 threshold 這個閾值,表示著交叉區域的比例值的,當你進入這個觀察區域的時候會觸發,當頁面內容往下填充,會把監聽目標元素往下推,又到達瞭這個閾值從而又觸發瞭一次。

解決方案很簡單,就是加一個 isLoading 開關,在請求中的時候,把根據這個開關把監聽目標隱藏掉,等加載渲染結束之後,再顯示出來,就可以解決這個問題瞭。具體可以看演示的案例哦~

<div class="loading">
    <div ref="loading" v-show="!isLoading"></div>
    loading..
</div>

結語

以異步觀察目標元素的方式來完成諸如此類的業務比如說分頁加載,觸發動畫,阻止操作等等都是不錯的選擇,而且從兼容性來看也可以放心在大多數現代瀏覽器中使用到它。

以上就是異步觀察目標元素方式完成分頁加載的詳細內容,更多關於異步觀察目標元素分頁加載的資料請關註WalkonNet其它相關文章!

推薦閱讀: