在移動端H5網頁中,下拉刷新和上拉加載更多數據的交互方式出現頻率很高,開源社區也有不少相似的解決方案,如iscroll,pulltorefresh.js庫等。下面是對這兩種常見交互基本實現原理的闡述。javascript
實現下拉刷新主要分爲三步:css
touchstart
事件,記錄其初始位置的值,e.touches[0].pageY
;touchmove
事件,記錄並計算當前滑動的位置值與初始位置值的差值,大於0
表示向下拉動,並藉助CSS3的translateY
屬性使元素跟隨手勢向下滑動對應的差值,同時也應設置一個容許滑動的最大值;touchend
事件,若此時元素滑動達到最大值,則觸發callback
,同時將translateY
重設爲0
,元素回到初始位置。
在下拉到鬆手的過程當中,經歷了三個狀態:html
上拉加載更多數據是在頁面滾動時觸發的動做,通常是頁面滾動到底部時觸發,也能夠選擇在滾動到必定位置的時候觸發。java
以滾動到頁面底部爲例。實現原理是分別得到當前滾動條的scrollTop
值、當前可視範圍的高度值clientHeight
以及文檔的總高度scrollHeight
。當scrollTop
和clientHeight
的值之和大於等於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