移動端 上拉刷新,下拉加載 效果

前言

在移動端H5網頁中,下拉刷新和上拉加載更多數據的交互方式出現頻率很高,開源社區也有不少相似的解決方案,如iscroll,pulltorefresh.js庫等。下面是對這兩種常見交互基本實現原理的闡述。javascript

實現原理

下拉刷新

實現下拉刷新主要分爲三步:css

  • 監聽原生touchstart事件,記錄其初始位置的值,e.touches[0].pageY
  • 監聽原生touchmove事件,記錄並計算當前滑動的位置值與初始位置值的差值,大於0表示向下拉動,並藉助CSS3的translateY屬性使元素跟隨手勢向下滑動對應的差值,同時也應設置一個容許滑動的最大值;
  • 監聽原生touchend事件,若此時元素滑動達到最大值,則觸發callback,同時將translateY重設爲0,元素回到初始位置。

 

在下拉到鬆手的過程當中,經歷了三個狀態:html

  • 當前手勢滑動位置與初始位置差值大於零時,提示正在進行下拉刷新操做;
  • 下拉到必定值時,顯示鬆手釋放後的操做提示;
  • 下拉到達設定最大值鬆手時,執行回調,提示正在進行更新操做。

上拉加載

上拉加載更多數據是在頁面滾動時觸發的動做,通常是頁面滾動到底部時觸發,也能夠選擇在滾動到必定位置的時候觸發。java

以滾動到頁面底部爲例。實現原理是分別得到當前滾動條的scrollTop值、當前可視範圍的高度值clientHeight以及文檔的總高度scrollHeight。當scrollTopclientHeight的值之和大於等於scrollHeight時,觸發callback函數

 

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>移動端上拉刷新、下拉加載</title>
	<style type="text/css">
		html,body,header,div,main,p,span,ul,li{ margin: 0; padding: 0; }
		#refreshContainer li{ background-color: #eee; margin-bottom: 1px; padding: 20px 10px; }
		.refreshText{ position: absolute; width: 100%; line-height: 50px; text-align: center; left: 0; top: 0; }
		.bot_refreshText{ line-height: 50px; text-align: center; }
	</style>
</head>
<body>
<main>
	<p class="refreshText"></p>
	<ul id="refreshContainer">
		<li>111</li>
		<li>222</li>
		<li>333</li>
		<li>444</li>
		<li>555</li>
		<li>111</li>
		<li>222</li>
		<li>333</li>
		<li>444</li>
		<li>555</li>
		<li>111</li>
		<li>222</li>
		<li>333</li>
		<li>444</li>
		<li>555</li>
	</ul>
	<p class="bot_refreshText"></p>
</main>

<!--上拉刷新-->
<script type="text/javascript">
	(function(window) {
		var _element = document.getElementById('refreshContainer'),
		  _refreshText = document.querySelector('.refreshText'),
		  _startPos = 0,
		  _transitionHeight = 0;
		_element.addEventListener('touchstart', function(e) {
			console.log('初始位置:', e.touches[0].pageY);
			_startPos = e.touches[0].pageY;
			_element.style.position = 'relative';
			_element.style.transition = 'transform 0s';
		}, false);
		
		_element.addEventListener('touchmove', function(e) {
			console.log('當前位置:', e.touches[0].pageY);
			_transitionHeight = e.touches[0].pageY - _startPos;
			
			if (_transitionHeight > 0 && _transitionHeight < 60) {
				_refreshText.innerText = '下拉刷新';
				_element.style.transform = 'translateY('+_transitionHeight+'px)';
				if (_transitionHeight > 55) {
				  _refreshText.innerText = '釋放更新';
				}
			}				
		}, false);
		_element.addEventListener('touchend', function(e) {
			_element.style.transition = 'transform 0.5s ease 1s';
			_element.style.transform = 'translateY(0px)';
			_refreshText.innerText = '更新中...';
			// todo...
		}, false);
	})(window);
</script>

<!--下拉加載-->
<script type="text/javascript">
(function(window) {
	// 獲取當前滾動條的位置 
    function getScrollTop() { 
	    var scrollTop = 0; 
	    if (document.documentElement && document.documentElement.scrollTop) { 
	    	scrollTop = document.documentElement.scrollTop; 
	    } else if (document.body) { 
	    	scrollTop = document.body.scrollTop; 
	    } 
	    return scrollTop; 
    } 
    // 獲取當前可視範圍的高度 
    function getClientHeight() { 
	    var clientHeight = 0; 
	    if (document.body.clientHeight && document.documentElement.clientHeight) { 
	    	clientHeight = Math.min(document.body.clientHeight, document.documentElement.clientHeight); 
	    } 
	    else { 
	    	clientHeight = Math.max(document.body.clientHeight, document.documentElement.clientHeight); 
	    } 
	    return clientHeight; 
    }
    // 獲取文檔完整的高度 
    function getScrollHeight() { 
    	return Math.max(document.body.scrollHeight, document.documentElement.scrollHeight); 
    }
    var _text = document.querySelector('.bot_refreshText'),
    _container = document.getElementById('refreshContainer');
    var throttle = function(method, context){
		  clearTimeout(method.tId);
		  method.tId = setTimeout(function(){
		    method.call(context);
		  }, 300);
	}
    function fetchData() {
    	setTimeout(function() {
    		_container.insertAdjacentHTML('beforeend', '<li>new add...</li>');
    	}, 1000);
    }
    window.onscroll = function() {
      	if (getScrollTop() + getClientHeight() == getScrollHeight()) {
      		_text.innerText = '加載中...';
      		throttle(fetchData);
      	}
    };
})(window);
</script>
</body>
</html>

  

 

小結

上拉刷新的實現主要依靠的是touch事件的三個階段,以及藉助CSS3動畫效果;下拉加載主要依靠頁面的onscroll事件,須要注意的是頁面滾動時可能要考慮函數節流。fetch

相關文章
相關標籤/搜索