vue 實現上拉載入下拉重新整理(思路賊清晰)

FZliweiliang發表於2018-08-27

專案需要用到上拉重新整理下拉載入 所以自己手動實現了一個 元件:

<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…

相關文章