Vue 滾動觸底 mixins

前言

在app端經常看到相似加載數據的動畫,接下來咱們來實現滾動觸底加載動畫提示,以及如何複用這些邏輯。

如何判斷滾動觸底

來看下幾張圖:vue

狀況一:

當文檔高度還爲超過可視區域高度時,不存在滾動,因此也沒有滾動觸底 編程

狀況二:

當文檔高度超過可視區域的高度時,還有剩餘的文檔沒有滾動完,也就是說可視區域高度 + 滾動高度 < 文檔高度,此時沒有達到滾動觸底的條件 promise

狀況三:

文檔高度大於可視區域,而且滾動到文檔底部, 也就是說 可視區域高度 + 滾動高度 = 文檔高度 bash

判斷是否滾動到底

通過上面三種狀況的分析,咱們須要拿到 可視區域的高度 , 滾動高度 , 文檔高度這三個變量來進行比較。app

可視區域的高度

function getWindowHeight() {
  return document.documentElement.clientHeight;
}
複製代碼

滾動高度

對有doctype申明的頁面使用document.documentElement.scrollTop,safari特例獨行:使用 window.pageYOffsetdom

function getScrollHeight() {
  return Math.max(document.documentElement.scrollTop,window.pageYOffset||0)
}
複製代碼

文檔高度

function getDocumentTop() {
  return document.documentElement.offsetHeight;
}
複製代碼

代碼實現

觸底打印

codepen 觸底打印demopost

  • 經過監聽滾動事件來判斷 可視區域滾動高度文檔高度的關係,實現最基礎的觸底加載
<div id="app">
   <ul>
      <li v-for="item in list" :key="item" > {{item}}</li>
    </ul>
 </div>
 created(){
      // 初始化數據
      this.list =  Array.from(Array(10),(item,index)=>index)
      // 經過監聽滾動事件來判斷 可視區域 , 滾動高度 ,文檔高度的關係
      window.addEventListener('scroll',()=>{
        let isBottom = (getScrollHeight() +  getWindowHeight()) >=  getDocumentTop()
        if(isBottom){
          console.log('觸底了',new Date())
          let list = this.list
          let last = list[list.length-1]
          let newList = Array.from(Array(10),(item,index)=>index+last+1)
          this.list.push(...newList)
        }
      })
  } 
複製代碼

優化和複用滾動事件邏輯

將滾動邏輯抽取成 mixins 放在 scroll.js 中。優化功能點以下:優化

  1. 增長觸底距離
  2. 滾動事件監聽事件節流
  3. 添加觸底動畫,並將 UI 樣式一塊兒封裝在 scroll.js 中

模擬請求事件

爲了模擬請求數據,封裝了一個 Promise 一秒後返回結果動畫

methods:{
  // 返回一個 promise ,用於請求服務端數據
  findDataList(){
    let list = this.list
    let last = list[list.length-1]
    return new Promise((resolve)=>{
    // 模擬服務端數據
    let newList = Array.from(Array(10),(item,index)=>index+last+1)
      setTimeout(() => {
        resolve(newList)
      }, 1000);
    })
  }
}
複製代碼

滾動事件監聽

滾動事件觸發,判斷當前是否觸底,觸底了之後去執行 loadMore 發起請求拿取服務端的數據ui

created(){
    let fn = throttle(()=>{
      let isOver = (getScrollHeight() +  getWindowHeight()) >=  (getDocumentTop()- MIN_INSTANCE)
      // 觸底時進行數據加載
      if(isOver){
        // 建立加載組件
        this.loadMore&&this.loadMore()
      }
    },DEALY_TIME)
    window.addEventListener('scroll',fn)
  },
複製代碼

添加觸底動畫

由於咱們是將邏輯抽離在 mixins中,爲了把觸底動畫也集成在裏面使用 Vue.extend() 來實現編程式插入UI樣式的方法。

  1. 首先定義好 loading 組件的樣式
<template>
    <div id="loading-alert">
      <i class="el-icon-loading"></i>
      <span>{{ message }}</span>
    </div>
</template>

<script>
export default {
  props:{
    message:{
      type:String,
      default:'正在加載更多數據'
    }
  },
};
複製代碼
  1. 當觸底時去插入這個 loading 組件
import load from './load.vue'
data(){
  return {
    isLoading:false,
    component:null
  }
},
created(){
  let fn = throttle(()=>{
    let isOver = (getScrollHeight() +  getWindowHeight()) >=  (getDocumentTop()- MIN_INSTANCE)
    // 觸底時進行load組件顯示
    if(isOver){
      // 判斷loading組件是否已經存在,不存在就建立一個
      if(!this.component){
        this.component = extendComponents(load)
      }
      // 建立加載組件
      this.loadMore&&this.loadMore()
      // 判斷當前狀態來控制loading的組件顯示與否
      if(!this.isLoading){
        this.component.$el.remove()
        // 將loading組件置爲空
        this.component = null
      }
    }
  },DEALY_TIME)
  window.addEventListener('scroll',fn)
},
複製代碼

詳細代碼

完整代碼能夠點擊查看 codepen 觸底動畫 關於上面代碼中 extendComponents 方法的實現能夠查看詳細代碼,也能夠查看 Vue.extend 編程式插入組件

最後

將滾動觸底的邏輯和 UI 都集成到 scroll.js 中,複用都方式能夠放在 mixins 能夠抽離成 v-directive,這樣咱們能夠接受到綁定的 dom 不單單能夠作 window 的滾動觸底事件的判斷,也能夠實現單個元素的滾動事件觸底的監聽。後續能夠在實現 v-directive 的版本。

相關文章
相關標籤/搜索