首頁 > 軟體

JS非同步觀察目標元素方式完成分頁載入

2022-07-29 22:04:29

介紹

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

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

程式碼

<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>

結語

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

以上就是非同步觀察目標元素方式完成分頁載入的詳細內容,更多關於非同步觀察目標元素分頁載入的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com