ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

vue项目中自己实现下拉刷新和上拉加载

2020-12-17 02:04:19  阅读:324  来源: 互联网

标签:vue angle let && 刷新 scrollTop document scrollHeight 加载


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>

标签:vue,angle,let,&&,刷新,scrollTop,document,scrollHeight,加载
来源: https://www.cnblogs.com/TRY0929/p/14147607.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有