Vue混入mixins滾動(dòng)觸底的方法
前言
在app端常常看到類似加載數(shù)據(jù)的動(dòng)畫,接下來(lái)我們來(lái)實(shí)現(xiàn)滾動(dòng)觸底加載動(dòng)畫提示,以及如何復(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)畫,并將 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)畫
因?yàn)槲覀兪菍⑦壿嫵殡x在 mixins中,為了把觸底動(dòng)畫也集成在里面使用 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)畫 關(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手寫一個(gè)簡(jiǎn)單的雙向綁定的示例
這篇文章主要介紹了用Object.defineProperty手寫一個(gè)簡(jiǎn)單的雙向綁定的示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-07-07
Vue設(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-06
Vue 計(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-10
Vue.js每天必學(xué)之計(jì)算屬性computed與$watch
Vue.js每天必學(xué)之計(jì)算屬性computed與$watch,為大家詳細(xì)講解計(jì)算屬性computed與$watch,感興趣的小伙伴們可以參考一下2016-09-09

