项目需要用到上拉刷新下拉加载 所以自己手动实现了一个
组件:
<template>
<div class="my-scroll" :class="[scrollState?'prohibit':'allow']" ref="myScroll" @scroll.passive="onScroll($event)" @touchstart="touchStart($event)" @touchmove="touchMove($event)" @touchend="touchEnd($event)" >
<div class="scroll-top" :style="{height:top+'px'}">
<div v-if="aspect==2">
<p v-if="state==6">
下拉刷新
p>
<p v-if="state==1">
<i><img :src="Load"/>i>
<br/>
刷新中
p>
<p v-if="state==2">松开刷新p>
<p v-if="state==3">
<i><img :src="Load"/>i>
<br/>
刷新完成
p>
div>
div>
<div class="scroll-list" :style="{ transform: 'translate3d(0, ' + top + 'px, 0)'}">
<slot name='scrollList'>slot>
<div class="scroll-bottom">
<div v-if="state==4">加载中div>
<div v-if="state==5">加载完成div>
<div v-if="state==7">没有更多div>
div>
div>
div>
template>
<script type="text/javascript">
import tween from '@/plugins/tween'
import Load from '@/assets/Load.gif'
export default {
name:'myScroll',
props:{
'page':{
type:Object, //counter:当前页 pageStart:开始页数 pageEnd:结束页数 total:总页数
},
'onRefresh':{ //刷新回调
type:Function,
require:true
},
'onPull':{ //加载回调
type:Function,
require:true
},
'getScrollTop':{ //获取滚动条位置
type:Function
},
'setScrollPage':{ //改变滚动条位置
type:Function
},
'scrollState':{//是否可滑动
type:Boolean,
require:true
}
},
data(){
return {
Load,
pageX:0,
pageY:0,
state:0,
scrollPosition:0,
myScroll:null,
myScrollList:null,
top:0,
aspect:0, //1:向下 2:向上
listHeight:0,
}
},
created(){
},
methods:{
ScrollTop(top){ //修改滚动条位置
this.myScroll.scrollTop = top
},
/*
* 刷新中:1
* 松开刷新:2
* 刷新完成:3
* 加载中:4
* 加载完成:5
* 下拉刷新:6
* 没有更多:7
*/
setState(index){ //修改状态
this.state = index
if(index == 5||index == 3){
setTimeout(()=>{
this.state = 0
let timer = null;
let that = this;
var b=50,c=100,d=100,t=0;
cancelAnimationFrame(timer);
timer = requestAnimationFrame(function fn() {
var oTop = that.top;
if (that.top>0) {
that.top = Math.ceil(tween.Quart.easeInOut(10,oTop,8,10)) - 15
timer = requestAnimationFrame(fn);
} else {
cancelAnimationFrame(timer);
that.top = 0
}
});
},500)
}
},
touchStart(e){ //触摸事件
this.pageX = e.targetTouches[0].pageX
this.pageY = e.targetTouches[0].pageY
},
touchMove(e){ //触摸滑动事件
this.scrollPosition = this.myScroll.scrollTop //获取滚动条位置
if(this.scrollState&&e.targetTouches[0].pageY>this.pageY){ //向上滑动
this.aspect = 2
if(this.myScroll.scrollTop==0){
let diff = e.targetTouches[0].pageY - this.pageY - this.scrollPosition
this.top = Math.pow(diff, 0.9)
let ranget = diff/document.body.clientHeight*100 //计算在屏幕上滑动了多少
if(ranget > 20){
this.state = 2
}else if(ranget < 15){
this.state = 6
}
e.preventDefault()
}
}else if(this.scrollState&&this.state!=4){ //向上滑动
this.aspect = 1
}
},
touchEnd(e){
if(this.aspect == 2&&this.state == 2||this.state == 1){ //上拉处理
this.top = 100
this.state = 1
this.topCallback()
}else if(this.aspect == 2){
this.state = 0
this.top = 0
}
},
onScroll(e){
let listHeight = this.myScrollList.offsetHeight //列表总高度
let listScrollTop = e.target.scrollTop + this.myScroll.offsetHeight //当前滚动条位置
if(this.state == 0&&listHeight-listScrollTop < 100){
this.bottomCallback()
}
if(this.getScrollTop)this.getScrollTop(e.target.scrollTop) //返回X,Y
},
topCallback(){ //刷新回调
this.onRefresh(this.state)
},
bottomCallback(){ //加载回调
if(this.state != 7){
this.state = 4
this.onPull(this.state)
}
},
},
mounted(){
this.myScroll = this.$refs.myScroll //获取滑条dom
this.myScrollList = this.myScroll.children[1] //获取列表dom
}
}
script>
<style lang="scss" scoped>
.allow{
overflow:hidden;
height: auto;
}
.prohibit{
max-width: 100%;
max-height: 100%;
height: 100%;
overflow:hidden;
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
will-change: transform;
transition: all 450ms;
backface-visibility: hidden;
perspective: 1000;
}
.my-scroll{
position: relative;
color: #fff;
.scroll-top{
text-align: center;
display:flex;
position:absolute;
top:0;
left:0;
width:100%;
overflow: hidden;
div{
display:flex;
height:auto;
width:100%;
justify-content: center;
align-items:center;
flex-wrap: wrap;
i{
flex:1 0 100%;
display:block;
height: 0.4rem;
}
img{
width:0.6rem;
}
p{
flex:1 0 100%;
}
}
}
.scroll-list{
overflow:hidden;
min-height: 100%;
}
.scroll-bottom{
text-align: center;
line-height: 40px;
}
}
style>
使用:
<template>
<div class="index">
<my-scroll ref="myScroll" :page="page" :on-refresh="onRefresh" :on-pull="onPull" :get-scroll-top="getTop">
<div slot="scrollList">
<ul>
<li v-for="(x,index) in list" :key="index">列表li>
ul>
div>
my-scroll>
div>
template>
<script type="text/javascript">
import myScroll from '@/components/myScroll.vue'
export default {
data(){
return{
list:[],
page:{
counter:1,
pageStart:1,
pageEnd:1,
total:10
},
}
},
methods:{
onRefresh(mun){ //刷新回调
setTimeout(()=>{
this.$refs.myScroll.setState(3);
},500)
},
onPull(mun){ //加载回调
if(this.page.counter<=this.page.total){
setTimeout(()=>{
this.page.counter++
this.$refs.myScroll.setState(5)
for(let i=0;i<10;i++){
this.listdata.push({})
}
},500)
}else{
this.$refs.myScroll.setState(7)
}
},
getTop(y) {//滚动条位置
},
},
components:{
myScroll
},
created(){
},
mounted(){
for(let i=0;i<1*50;i++){
this.list.push({})
}
},
}
script>
<style lang="scss" scoped>
.index{
}
style>
上拉刷新实现思路:
1.通过touchstart获取用户第一次点击的坐标
2.通过touchmove 判断向上滑动还是向下
4.判断列表的滚动条是否在最顶部
5.然后判断在这个屏幕滑动的比例 进行状态显示
下拉加载实现思路:
1.通过判断滚动条位置实现下拉加载
样式:
注:缓动算法与tween.js 来自 https://www.cnblogs.com/cloudgamer/archive/2009/01/06/Tween.html 详细用法这里都有
github地址:https://github.com/FZliweiliang/vue-scroll