專案需要用到上拉重新整理下拉載入 所以自己手動實現了一個 元件:
<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>
<!-- top -->
<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 來自 www.cnblogs.com/cloudgamer/… 詳細用法這裡都有
github地址:github.com/FZliweilian…