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>
标签:vue,angle,let,&&,刷新,scrollTop,document,scrollHeight,加载 来源: https://www.cnblogs.com/TRY0929/p/14147607.html