Vue混入mixins滾動(dòng)觸底的方法
前言
在app端常??吹筋?lèi)似加載數(shù)據(jù)的動(dòng)畫(huà),接下來(lái)我們來(lái)實(shí)現(xiàn)滾動(dòng)觸底加載動(dòng)畫(huà)提示,以及如何復(fù)用這些邏輯。
如何判斷滾動(dòng)觸底
來(lái)看下幾張圖:
情況一:
當(dāng)文檔高度還為超過(guò)可視區(qū)域高度時(shí),不存在滾動(dòng),所以也沒(méi)有滾動(dòng)觸底
情況二:
當(dāng)文檔高度超過(guò)可視區(qū)域的高度時(shí),還有剩余的文檔沒(méi)有滾動(dòng)完,也就是說(shuō) 可視區(qū)域高度 + 滾動(dòng)高度 < 文檔高度
,此時(shí)沒(méi)有達(dá)到滾動(dòng)觸底的條件
情況三:
文檔高度大于可視區(qū)域,并且滾動(dòng)到文檔底部, 也就是說(shuō) 可視區(qū)域高度 + 滾動(dòng)高度 = 文檔高度
判斷是否滾動(dòng)到底
經(jīng)過(guò)上面三種情況的分析,我們需要拿到 可視區(qū)域的高度
, 滾動(dòng)高度
, 文檔高度
這三個(gè)變量來(lái)進(jìn)行比較。
可視區(qū)域的高度
function getWindowHeight() { return document.documentElement.clientHeight; }
滾動(dòng)高度
對(duì)有doctype申明的頁(yè)面使用document.documentElement.scrollTop,safari特例獨(dú)行:使用 window.pageYOffset
function getScrollHeight() { return Math.max(document.documentElement.scrollTop,window.pageYOffset||0) }
文檔高度
function getDocumentTop() { return document.documentElement.offsetHeight; }
代碼實(shí)現(xiàn)
觸底打印
通過(guò)監(jiān)聽(tīng)滾動(dòng)事件來(lái)判斷 可視區(qū)域
, 滾動(dòng)高度
, 文檔高度
的關(guān)系,實(shí)現(xiàn)最基礎(chǔ)的觸底加載
<div id="app"> <ul> <li v-for="item in list" :key="item" > {{item}}</li> </ul> </div> created(){ // 初始化數(shù)據(jù) this.list = Array.from(Array(10),(item,index)=>index) // 通過(guò)監(jiān)聽(tīng)滾動(dòng)事件來(lái)判斷 可視區(qū)域 , 滾動(dòng)高度 ,文檔高度的關(guān)系 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) } }) }
優(yōu)化和復(fù)用滾動(dòng)事件邏輯
將滾動(dòng)邏輯抽取成 mixins 放在 scroll.js 中。優(yōu)化功能點(diǎn)如下:
- 增加觸底距離
- 滾動(dòng)事件監(jiān)聽(tīng)事件節(jié)流
- 添加觸底動(dòng)畫(huà),并將 UI 樣式一起封裝在 scroll.js 中
模擬請(qǐng)求事件
為了模擬請(qǐng)求數(shù)據(jù),封裝了一個(gè) Promise 一秒后返回結(jié)果
methods:{ // 返回一個(gè) promise ,用于請(qǐng)求服務(wù)端數(shù)據(jù) findDataList(){ let list = this.list let last = list[list.length-1] return new Promise((resolve)=>{ // 模擬服務(wù)端數(shù)據(jù) let newList = Array.from(Array(10),(item,index)=>index+last+1) setTimeout(() => { resolve(newList) }, 1000); }) } }
滾動(dòng)事件監(jiān)聽(tīng)
滾動(dòng)事件觸發(fā),判斷當(dāng)前是否觸底,觸底了以后去執(zhí)行 loadMore 發(fā)起請(qǐng)求拿取服務(wù)端的數(shù)據(jù)
created(){ let fn = throttle(()=>{ let isOver = (getScrollHeight() + getWindowHeight()) >= (getDocumentTop()- MIN_INSTANCE) // 觸底時(shí)進(jìn)行數(shù)據(jù)加載 if(isOver){ // 創(chuàng)建加載組件 this.loadMore&&this.loadMore() } },DEALY_TIME) window.addEventListener('scroll',fn) },
添加觸底動(dòng)畫(huà)
因?yàn)槲覀兪菍⑦壿嫵殡x在 mixins中,為了把觸底動(dòng)畫(huà)也集成在里面使用 Vue.extend() 來(lái)實(shí)現(xiàn)編程式插入U(xiǎn)I樣式的方法。
首先定義好 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:'正在加載更多數(shù)據(jù)' } }, };
當(dāng)觸底時(shí)去插入這個(gè) loading 組件
import load from './load.vue' data(){ return { isLoading:false, component:null } }, created(){ let fn = throttle(()=>{ let isOver = (getScrollHeight() + getWindowHeight()) >= (getDocumentTop()- MIN_INSTANCE) // 觸底時(shí)進(jìn)行l(wèi)oad組件顯示 if(isOver){ // 判斷l(xiāng)oading組件是否已經(jīng)存在,不存在就創(chuàng)建一個(gè) if(!this.component){ this.component = extendComponents(load) } // 創(chuàng)建加載組件 this.loadMore&&this.loadMore() // 判斷當(dāng)前狀態(tài)來(lái)控制loading的組件顯示與否 if(!this.isLoading){ this.component.$el.remove() // 將loading組件置為空 this.component = null } } },DEALY_TIME) window.addEventListener('scroll',fn) },
詳細(xì)代碼
完整代碼可以 點(diǎn)擊查看 codepen 觸底動(dòng)畫(huà) 關(guān)于上面代碼中 extendComponents
方法的實(shí)現(xiàn)可以查看詳細(xì)代碼,也可以查看 Vue.extend 編程式插入組件
最后
將滾動(dòng)觸底的邏輯和 UI 都集成到 scroll.js 中,復(fù)用都方式可以放在 mixins 可以抽離成 v-directive,這樣我們可以接受到綁定的 dom 不僅僅可以做 window 的滾動(dòng)觸底事件的判斷,也可以 實(shí)現(xiàn)單個(gè)元素的滾動(dòng)事件觸底的監(jiān)聽(tīng)
。后續(xù)可以在實(shí)現(xiàn) v-directive 的版本。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
vue用Object.defineProperty手寫(xiě)一個(gè)簡(jiǎn)單的雙向綁定的示例
這篇文章主要介紹了用Object.defineProperty手寫(xiě)一個(gè)簡(jiǎn)單的雙向綁定的示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-07-07Vue設(shè)置keepAlive不生效問(wèn)題及解決
這篇文章主要介紹了Vue設(shè)置keepAlive不生效問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04前端使用vue實(shí)現(xiàn)token無(wú)感刷新的三種方案解析
這篇文章主要為大家介紹了前端使用vue實(shí)現(xiàn)token無(wú)感刷新的三種方案詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06Vue 計(jì)數(shù)器的實(shí)現(xiàn)
這篇文章主要介紹了Vue 計(jì)數(shù)器的實(shí)現(xiàn),主要利用HTML實(shí)現(xiàn)步驟現(xiàn)在頁(yè)面上簡(jiǎn)單實(shí)現(xiàn)一個(gè)計(jì)數(shù)器,內(nèi)容簡(jiǎn)單且詳細(xì),需要的朋友可以參考一下2021-10-10Vue.js每天必學(xué)之計(jì)算屬性computed與$watch
Vue.js每天必學(xué)之計(jì)算屬性computed與$watch,為大家詳細(xì)講解計(jì)算屬性computed與$watch,感興趣的小伙伴們可以參考一下2016-09-09