vue項目中自己實現下拉刷新和上拉加載


vue項目中自己實現下拉刷新和上拉加載

1、頁面監聽版(簡單)

在mounted里監聽頁面滾動

其實是只要監聽滾動盒子的scroll事件即可,但有的時候滾動的是整個頁面,那我們就直接監聽window的滾動就可以:

window.addEventListener('scroll', this.onContentScroll)

監聽頁面滾動事件

  • 獲取當前滾動的高度scrollTop(代碼里這種寫法好好理解並記憶,囊括了各種情況);

  • 獲取當前可視高度clientHeight;

  • 獲取當前整個頁面(包括可滾動區域,其實就是滾動的整個盒子)的高度scrollHeight;

  • scrollTop + clientHeight >= scrollHeight時即可證明滑到底部了;

    • 這里減二是為了消除像素在瀏覽器里顯示時候出現的小小誤差;
  • 滑動到底部看當前是否有更多數據(hasMore)可獲得以及當前是否正在獲取數據(busy)

onContentScroll (e) {
  let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
  let clientHeight = document.documentElement.clientHeight;
  let scrollHeight = document.documentElement.scrollHeight;
  if (scrollTop + clientHeight >= scrollHeight-2) {
    if (this.hasMore && !this.busy) {
      this.loadMore()
    }
  }
},

加載更多(loadMore)函數

  • 設置當前處於正在加載狀態(busy置為true),其實相當於加了把鎖(最近學os學傻了...;
  • 獲取更多數據,且在回調里將加載狀態消除。
loadMore () {
  this.busy = true
  this.page++
  this.getJobList()
    .then(() => {
      this.busy = false
    })
}

2、另寫組件版(略復雜)

就不仔仔細細講了,原理和上面的簡單版差不多,只是擴充了一些內容以及加上手勢操作。

  • 監聽頁面的touchstart和touchend事件

  • 在touchstart中記錄下手指開始滑動的位置;

  • 在touchend中記錄下手指結束滑動的位置;

  • 將開始和結束位置進行比較:

    • 先判斷滑動方向(上拉刷新,下拉加載),這一步還挺復雜 主要是判斷手指的各種滑動情況比較復雜;
    • 若是上拉就看是否滑到底部,這一步的話主要是計算各種盒子的高度比較麻煩思路其實不難,難在布局;
    • 若是下拉就看當前距離頂部的高度(其實就是上面簡單版里的scrollTop),若為0了說明回到原位,開始刷新。

附源代碼:

<template>
	<div class="loadmoreBox flex flexh flexvc" @touchstart="touchStart($event)"  @touchend="touchEnd($event)">
		<div class="refreshBox flex flexc" v-if="refresh">
			<van-loading class="refreshLoading" type="spinner" />
		</div>
		<slot></slot>
		<div class="loadmore" v-if="status==1">上拉加載更多...</div>
		<van-loading class="loadmore" v-else-if="status==2" type="spinner" />
		<div class="loadmore" v-else-if="status==3">我是有底線的</div>
	</div>
</template>

<script>
import { Loading as VanLoading } from 'vant';
export default {
	name: 'LoadMore',
	props:{
		refresh:{
			type:Boolean,
			default:false
		},
		status:{
			type:Number,
			default:0
		}
	},
	data(){
		return {
			startX:0,
			startY:0,
		}
	},
	
	components:{
		VanLoading
	},
	methods:{
		touchStart(e){
			this.startY = e.targetTouches[0].pageY;
			this.startX = e.targetTouches[0].pageX;  
		},
		touchEnd(e){
			let endY = e.changedTouches[0].pageY;
			let endX = e.changedTouches[0].pageX; 
			let direct=this.getSlideDirection(this.startX,this.startY,endX,endY);
			console.log(direct);
			if(direct==1){ //上拉加載
				let isEnd=this.scrollToTheEnd();
				if(isEnd&&this.status==1){
					this.$emit('loadMore');
				}
			}else if(direct==2){ //下拉刷新
				// 獲取滾動條距離頂部的距離
				let scrollToTop = document.documentElement.scrollTop || document.body.scrollTop || window.pageYOffset;
				if(!scrollToTop){
					this.$emit('onRefresh');
				}
			}	
		},
		/**
		* 判斷滾動條是否到底
		*/
		scrollToTheEnd () {
			//獲取窗口的高度
			let clientHeight = document.documentElement.clientHeight;
			//獲取滾動元素距離文檔 頂部的距離
			let elementTop=document.querySelector('.loadmoreBox').offsetTop;
			//獲取滾動元素高度
			let elementHeight=document.querySelector('.loadmoreBox').offsetHeight;
			
			//獲取頂部固定區域高度
			let topFixEl=document.querySelector('.topFixBlank');
			let topFixHeight=topFixEl?topFixEl.offsetHeight:0;
			
			//獲取加載板塊高度
			let loadmoreEl=document.querySelector('.loadmore');
			let loadmoreH=loadmoreEl?loadmoreEl.offsetHeight:0;
			// 獲取滾動條距離頂部的距離
			let scrollToTop = document.documentElement.scrollTop || document.body.scrollTop || window.pageYOffset 
			// 獲取滾動條的總高度
			let scrollHeight = document.documentElement.scrollHeight  || document.body.scrollHeight
			//整個列表的高度
			let pageHeight=elementTop+elementHeight-topFixHeight-loadmoreH;
			//判斷是否到底
			if(pageHeight+Math.ceil(scrollToTop)>scrollHeight){ //如果列表高度+滾動距離大於滾動條高度,則代表到底了
				return true;
			}else{
				return false;
			}
		},
		/**
		* 返回角度
		*/
		getSlideAngle (dx, dy) {
			return Math.atan2(dy, dx) * 180 / Math.PI
		},
		/**
		 * 根據起點和終點返回方向 1:向上,2:向下,3:向左,4:向右,0:未滑動
		 * @param {number} startX X軸開始位置
		 * @param {number} startY X軸結束位置
		 * @param {number} endX Y軸開始位置
		 * @param {number} endY Y軸結束位置
		 */
		getSlideDirection (startX, startY, endX, endY) {
			let dy = startY - endY
			let dx = endX - startX
			let result = 0
			// 如果滑動距離太短
			if (Math.abs(dx) < 2 && Math.abs(dy) < 2) {
				return result
			}
			let angle = this.getSlideAngle(dx, dy)
			if (angle >= -30 && angle < 30) {
				result = 4
			} else if (angle >= 30 && angle < 150) {
				result = 1
			} else if (angle >= -150 && angle < -30) {
				result = 2
			} else if ((angle >= 150 && angle <= 180) || (angle >= -180 && angle < -150)) {
				result = 3
			}
			return result
		}
	}
}
</script>
<style lang="scss" scoped="scoped">
.refreshBox{
	width: 100%;
	height: auto;
	overflow: hidden;
	margin-bottom: 10px;
}
.refreshLoading{
	width: 20px;
	height:20px;
}
.loadmoreBox{
	width: 100%;
	height:auto;
}
.loadmore{
	width: 100%;
	height: 30px;
	text-align: center;
	line-height: 30px;
	font-size: 14px;
	color: #666666;
}
</style>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM