基于vue2實(shí)現(xiàn)上拉加載功能
本文實(shí)例為大家分享了vue2實(shí)現(xiàn)上拉加載展示的具體代碼,供大家參考,具體內(nèi)容如下
因?yàn)槲覀冺?xiàng)目中,還用了swiper。很多都是滑動(dòng)切換的,但是又得上拉加載,所以導(dǎo)致,很多UI框架,我們用了,都有不同的bug出現(xiàn),沒(méi)辦法,最后寫(xiě)了一個(gè)。代碼如下(這個(gè)因?yàn)楹芏嗟胤綍?huì)用,所以建議放在components/common下面):
<template>
<div class="loadmore">
<slot></slot>
<slot name="bottom">
</slot>
</div>
</template>
<style>
.loadmore{
width:100%;
}
</style>
<script>
export default {
name: 'loadmore',
props: {
maxDistance: {
type: Number,
default: 0
},
autoFill: {
type: Boolean,
default: true
},
distanceIndex: {
type: Number,
default: 2
},
bottomPullText: {
type: String,
default: '上拉刷新'
},
bottomDropText: {
type: String,
default: '釋放更新'
},
bottomLoadingText: {
type: String,
default: '加載中...'
},
bottomDistance: {
type: Number,
default: 70
},
bottomMethod: {
type: Function
},
bottomAllLoaded: {
type: Boolean,
default: false
},
},
data() {
return {
// 最下面出現(xiàn)的div的位移
translate: 0,
// 選擇滾動(dòng)事件的監(jiān)聽(tīng)對(duì)象
scrollEventTarget: null,
containerFilled: false,
bottomText: '',
// class類名
bottomDropped: false,
// 獲取監(jiān)聽(tīng)滾動(dòng)元素的scrollTop
bottomReached: false,
// 滑動(dòng)的方向 down---向下互動(dòng);up---向上滑動(dòng)
direction: '',
startY: 0,
startScrollTop: 0,
// 實(shí)時(shí)的clientY位置
currentY: 0,
topStatus: '',
// 上拉加載的狀態(tài) '' pull: 上拉中
bottomStatus: '',
};
},
watch: {
// 改變當(dāng)前加載在狀態(tài)
bottomStatus(val) {
this.$emit('bottom-status-change', val);
switch (val) {
case 'pull':
this.bottomText = this.bottomPullText;
break;
case 'drop':
this.bottomText = this.bottomDropText;
break;
case 'loading':
this.bottomText = this.bottomLoadingText;
break;
}
}
},
methods: {
onBottomLoaded() {
this.bottomStatus = 'pull';
this.bottomDropped = false;
this.$nextTick(() => {
if (this.scrollEventTarget === window) {
document.body.scrollTop += 50;
} else {
this.scrollEventTarget.scrollTop += 50;
}
this.translate = 0;
});
// 注釋
if (!this.bottomAllLoaded && !this.containerFilled) {
this.fillContainer();
}
},
getScrollEventTarget(element) {
let currentNode = element;
while (currentNode && currentNode.tagName !== 'HTML' &&
currentNode.tagName !== 'BODY' && currentNode.nodeType === 1) {
let overflowY = document.defaultView.getComputedStyle(currentNode).overflowY;
if (overflowY === 'scroll' || overflowY === 'auto') {
return currentNode;
}
currentNode = currentNode.parentNode;
}
return window;
},
// 獲取scrollTop
getScrollTop(element) {
if (element === window) {
return Math.max(window.pageYOffset || 0, document.documentElement.scrollTop);
} else {
return element.scrollTop;
}
},
bindTouchEvents() {
this.$el.addEventListener('touchstart', this.handleTouchStart);
this.$el.addEventListener('touchmove', this.handleTouchMove);
this.$el.addEventListener('touchend', this.handleTouchEnd);
},
init() {
this.bottomStatus = 'pull';
// 選擇滾動(dòng)事件的監(jiān)聽(tīng)對(duì)象
this.scrollEventTarget = this.getScrollEventTarget(this.$el);
if (typeof this.bottomMethod === 'function') {
// autoFill 屬性的實(shí)現(xiàn) 注釋
this.fillContainer();
// 綁定滑動(dòng)事件
this.bindTouchEvents();
}
},
// autoFill 屬性的實(shí)現(xiàn) 注釋
fillContainer() {
if (this.autoFill) {
this.$nextTick(() => {
if (this.scrollEventTarget === window) {
this.containerFilled = this.$el.getBoundingClientRect().bottom >=
document.documentElement.getBoundingClientRect().bottom;
} else {
this.containerFilled = this.$el.getBoundingClientRect().bottom >=
this.scrollEventTarget.getBoundingClientRect().bottom;
}
if (!this.containerFilled) {
this.bottomStatus = 'loading';
this.bottomMethod();
}
});
}
},
// 獲取監(jiān)聽(tīng)滾動(dòng)元素的scrollTop
checkBottomReached() {
if (this.scrollEventTarget === window) {
return document.body.scrollTop + document.documentElement.clientHeight >= document.body.scrollHeight;
} else {
// getBoundingClientRect用于獲得頁(yè)面中某個(gè)元素的左,上,右和下分別相對(duì)瀏覽器視窗的位置。 right是指元素右邊界距窗口最左邊的距離,bottom是指元素下邊界距窗口最上面的距離。
return this.$el.getBoundingClientRect().bottom <= this.scrollEventTarget.getBoundingClientRect().bottom + 1;
}
},
// ontouchstart 事件
handleTouchStart(event) {
// 獲取起點(diǎn)的y坐標(biāo)
this.startY = event.touches[0].clientY;
this.startScrollTop = this.getScrollTop(this.scrollEventTarget);
this.bottomReached = false;
if (this.bottomStatus !== 'loading') {
this.bottomStatus = 'pull';
this.bottomDropped = false;
}
},
// ontouchmove事件
handleTouchMove(event) {
if (this.startY < this.$el.getBoundingClientRect().top && this.startY > this.$el.getBoundingClientRect().bottom) {
// 沒(méi)有在需要滾動(dòng)的范圍內(nèi)滾動(dòng),不再監(jiān)聽(tīng)scroll
return;
}
// 實(shí)時(shí)的clientY位置
this.currentY = event.touches[0].clientY;
// distance 移動(dòng)位置和開(kāi)始位置的差值 distanceIndex---
let distance = (this.currentY - this.startY) / this.distanceIndex;
// 根據(jù) distance 判斷滑動(dòng)的方向 并賦予變量 direction down---向下互動(dòng);up---向上滑動(dòng)
this.direction = distance > 0 ? 'down' : 'up';
if (this.direction === 'up') {
// 獲取監(jiān)聽(tīng)滾動(dòng)元素的scrollTop
this.bottomReached = this.bottomReached || this.checkBottomReached();
}
if (typeof this.bottomMethod === 'function' && this.direction === 'up' &&
this.bottomReached && this.bottomStatus !== 'loading' && !this.bottomAllLoaded) {
// 有加載函數(shù),是向上拉,有滾動(dòng)距離,不是正在加載ajax,沒(méi)有加載到最后一頁(yè)
event.preventDefault();
event.stopPropagation();
if (this.maxDistance > 0) {
this.translate = Math.abs(distance) <= this.maxDistance
? this.getScrollTop(this.scrollEventTarget) - this.startScrollTop + distance : this.translate;
} else {
this.translate = this.getScrollTop(this.scrollEventTarget) - this.startScrollTop + distance;
}
if (this.translate > 0) {
this.translate = 0;
}
this.bottomStatus = -this.translate >= this.bottomDistance ? 'drop' : 'pull';
}
},
// ontouchend事件
handleTouchEnd() {
if (this.direction === 'up' && this.bottomReached && this.translate < 0) {
this.bottomDropped = true;
this.bottomReached = false;
if (this.bottomStatus === 'drop') {
this.translate = '-50';
this.bottomStatus = 'loading';
this.bottomMethod();
} else {
this.translate = '0';
this.bottomStatus = 'pull';
}
}
this.direction = '';
}
},
mounted() {
this.init();
}
};
</script>
然后哪個(gè)頁(yè)面需要,在哪個(gè)頁(yè)面導(dǎo)入即可:import LoadMore from './../common/loadmore.vue';在需要引入他的頁(yè)面寫(xiě)法如下:
<template>
<section class="finan">
<!-- 上拉加載更多 -->
<load-more
:bottom-method="loadBottom"
:bottom-all-loaded="allLoaded"
:bottomPullText='bottomText'
:auto-fill="false"
@bottom-status-change="handleBottomChange"
ref="loadmore">
<div>
這里寫(xiě)你需要的另外的模塊
</div>
<div v-show="loading" slot="bottom" class="loading"> 這個(gè)div是為讓上拉加載的時(shí)候顯示一張加載的gif圖
<img src="./../../assets/main/uploading.gif">
</div>
</load-more>
</section>
</template>
然后在此頁(yè)面的data里和methods設(shè)置如下:
export default {
name: 'FinancialGroup',
props:{
},
data () {
return {
// 上拉加載數(shù)據(jù)
scrollHeight: 0,
scrollTop: 0,
containerHeight: 0,
loading: false,
allLoaded: false,
bottomText: '上拉加載更多...',
bottomStatus: '',
pageNo: 1,
totalCount: '',
}
},
methods: {
/* 下拉加載 */
_scroll: function(ev) {
ev = ev || event;
this.scrollHeight = this.$refs.innerScroll.scrollHeight;
this.scrollTop = this.$refs.innerScroll.scrollTop;
this.containerHeight = this.$refs.innerScroll.offsetHeight;
},
loadBottom: function() {
this.loading = true;
this.pageNo += 1; // 每次更迭加載的頁(yè)數(shù)
if (this.pageNo == this.totalGetCount) {
// 當(dāng)allLoaded = true時(shí)上拉加載停止
this.loading = false;
this.allLoaded = true;
}
api.commonApi(后臺(tái)接口,請(qǐng)求參數(shù)) 這個(gè)api是封裝的axios有不懂的可以看vue2+vuex+axios那篇文章
.then(res => {
setTimeout(() => {
要使用的后臺(tái)返回的數(shù)據(jù)寫(xiě)在setTimeout里面
this.$nextTick(() => {
this.loading = false;
})
}, 1000)
});
},
handleBottomChange(status) {
this.bottomStatus = status;
},
}
這樣就完成了。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
把vue-router和express項(xiàng)目部署到服務(wù)器的方法
下面小編就為大家分享一篇把vue-router和express項(xiàng)目部署到服務(wù)器的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-02-02
element-plus日歷(Calendar)動(dòng)態(tài)渲染以及避坑指南
這篇文章主要給大家介紹了關(guān)于element-plus日歷(Calendar)動(dòng)態(tài)渲染以及避坑指南的相關(guān)資料,這是最近幫一個(gè)后端朋友處理一個(gè)前端問(wèn)題,elementUI中calendar日歷組件內(nèi)容進(jìn)行自定義顯示,實(shí)現(xiàn)類似通知事項(xiàng)的日歷效果,需要的朋友可以參考下2023-08-08
VueJs使用Amaze ui調(diào)整列表和內(nèi)容頁(yè)面
這篇文章主要介紹了VueJs 填坑日記之使用Amaze ui調(diào)整列表和內(nèi)容頁(yè)面,需要的朋友可以參考下2017-11-11
ElementUI組件Dialog彈窗再次打開(kāi)表單仍顯示上次數(shù)據(jù)的問(wèn)題
這篇文章主要介紹了ElementUI組件Dialog彈窗再次打開(kāi)表單仍顯示上次數(shù)據(jù)的問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04
尤雨溪開(kāi)發(fā)vue?dev?server理解vite原理
這篇文章主要為大家介紹了尤雨溪開(kāi)發(fā)的玩具vite,vue-dev-server來(lái)理解vite原理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
vue3無(wú)config文件夾打包后頁(yè)面空白問(wèn)題及解決
這篇文章主要介紹了vue3無(wú)config文件夾打包后頁(yè)面空白問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05
vue結(jié)合v-for和input實(shí)現(xiàn)多選列表checkbox功能
在Vue中,可通過(guò)v-for指令和v-model實(shí)現(xiàn)多選列表功能,首先,使用v-for指令遍歷數(shù)組生成列表項(xiàng),每個(gè)列表項(xiàng)包含一個(gè)復(fù)選框,復(fù)選框的v-model綁定到一個(gè)數(shù)組變量,用于存儲(chǔ)選中的值,感興趣的朋友跟隨小編一起看看吧2024-09-09
解決vue動(dòng)態(tài)為數(shù)據(jù)添加新屬性遇到的問(wèn)題
今天小編就為大家分享一篇解決vue動(dòng)態(tài)為數(shù)據(jù)添加新屬性遇到的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-09-09

