用vue寫一個仿app下拉刷新的組件


如果你用vue弄移動端的頁面,那么下拉刷新還是比較常見的場景,下面來研究如何寫一個下拉刷新的組件(先上圖);

由於節省大家的時間,樣式就不貼出來了。

html結構也不必介紹了,直接看代碼吧-.-

        <transition>
		<div class="refresh-wrapper" ref="refresh">
			<div class="refresh-inner">
				<div class="refresh-pull" v-show="state==='pull'">
					<span>下拉刷新-.-</span>
				</div>
				<div class="refresh-loading" v-show="state==='loading'">
					<span>刷新中...~.~</span>
				</div>
				
				<div class="refresh-end" v-show="state==='end'">
					<span>刷新完成!^.^</span>
				</div>
			</div>
			
		</div>
	</transition>
		    

核心思路及步驟

  1. document綁定touch事件
document.addEventListener('touchstart',this.touchStart,false);
document.addEventListener('touchmove',this.touchMove,false);
document.body.addEventListener('touchend',this.touchEnd,false);
  1. touchStart細節
    2.1 判斷狀態,這是為了防止在刷新時多次觸發。可以定義一個變量保存狀態,狀態值為pull, loading, end;
    2.2 記錄開始的位置,Y軸的就可以了;
    2.3 獲取當前touch的對象? 雖然我們已經把事件綁定在document上了,但是在有局部滾動的時候,那么向下滑動的時候就會有沖突,這個時候可以獲取到當前touch的對象,后面做處理;
touchStart(e){
	if(this.state === 'loading') return;

	this.startY = e.touches[0].clientY;
	this.getTouchTarget(e.target);
		
}

getTouchTarget(elm){
	let currentNode = elm;
	while(currentNode && currentNode.tagName !== "HTML" &&
		currentNode.tagName !== "BODY" && currentNode.nodeType === 1){
		let overflowY = window.getComputedStyle(currentNode).overflowY;
			if(overflowY === "scroll" || overflowY === "auto"){
				this.currentNode = currentNode;
				this.firstNode = currentNode.firstElementChild; //記錄局部滾動的第一個子元素
				break;
			}
			currentNode = currentNode.parentNode;
            }
			
}
  1. touchMove細節
    3.1 判斷當前滑動的區域是否局部滾動,如果是,通過判斷父元素和子元素的getBoundingClientRect().top的差值是否小於0來判斷是否滾動到頂部
    3.2 判斷一些其他的條件
    3.3 記錄滑動的距離
    3.4 改變視圖
touchMove(e){
			let firstTop=0,  currentTop=0;
			if(this.firstNode){ 
				firstTop = this.firstNode.getBoundingClientRect().top;
			 	currentTop = this.currentNode.getBoundingClientRect().top;	
			}
			 let range = (e.touches[0].clientY - this.startY);
			if( document.documentElement.scrollTop>0 || this.state === 'loading' || firstTop-currentTop <0 || range<0) return;
			

			range = range*0.75 > this.maxRange? this.maxRange : range;
			
			this.translate = range;
			this.changeView();

}

changeView(){
        //這里針對transfrom對fixed定位的bug做的降級處理
	if(this.isFixed){
		this.$refs.refresh.style.transform=`translate3d(0,${this.translate}px,0)`;
	}else{
		document.body.style.transform = `translate3d(0,${this.translate}px,0)`;
	}
}
  1. touchEnd細節
    4.1 判斷狀態
    4.2 判斷滑動距離是否到可刷新距離,如果是,調用刷新api
    4.3 改變視圖
touchEnd(e){
			if(this.state === 'loading') return;
			
			if(this.translate && this.translate >= this.maxRange){
				this.translate = this.maxRange/2;
				
				this.refresh();
			}else{
				this.translate = 0;
			}
			this.rotate = 0;
			this.changeView();
}

refresh(){
		this.state = 'loading';
		console.log('更新中...');
		this.$emit('refresh'); //父組件監聽refresh方法,並在異步回調中調用子組件的refreshEnd方法,可通過this.$refs.名稱.refreshEnd()方法調用

}

refreshEnd(){
			let _this = this;
			this.state = 'end';

			setTimeout(()=>{

				_this.translate = 0;
				_this.changeView();
			},1000);

			setTimeout(()=>{
				_this.state = 'pull';
			},1300)
			
			console.log('更新完成...');
		}

注意

1.如果有fixed布局,要傳isFixed='true',否則會有bug。關於transform 與fixed的bug,可以參考這里
2. 不建議用在過於復雜的布局,可能有未知bug -.-

源代碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM