iscroll-pull-up-down.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. var IScrollPullUpDown = function (wrapperName,iScrollConfig,pullDownActionHandler,pullUpActionHandler) {
  2. var iScrollConfig,pullDownActionHandler,pullUpActionHandler,pullDownEl,pullDownOffset,pullUpEl,scrollStartPos;
  3. var pullThreshold=5;
  4. var me=this;
  5. function showPullDownElNow(className) {
  6. // Shows pullDownEl with a given className
  7. pullDownEl.style.transitionDuration='';
  8. pullDownEl.style.marginTop='';
  9. pullDownEl.className = 'pullDown '+className;
  10. }
  11. var hidePullDownEl = function (time,refresh) {
  12. // Hides pullDownEl
  13. pullDownEl.style.transitionDuration=(time>0?time+'ms':'');
  14. pullDownEl.style.marginTop='';
  15. pullDownEl.className = 'pullDown scrolledUp';
  16. // If refresh==true, refresh again after time+10 ms to update iScroll's "scroller.offsetHeight" after the pull-down-bar is really hidden...
  17. // Don't refresh when the user is still dragging, as this will cause the content to jump (i.e. don't refresh while dragging)
  18. if (refresh) setTimeout(function(){me.myScroll.refresh();},time+10);
  19. }
  20. function init() {
  21. var wrapperObj = document.querySelector('#'+wrapperName);
  22. var scrollerObj = wrapperObj.children[0];
  23. if (pullDownActionHandler) {
  24. // If a pullDownActionHandler-function is supplied, add a pull-down bar at the top and enable pull-down-to-refresh.
  25. // (if pullDownActionHandler==null this iScroll will have no pull-down-functionality)
  26. pullDownEl=document.createElement('div');
  27. pullDownEl.className='pullDown scrolledUp';
  28. pullDownEl.innerHTML='<span class="pullDownIcon"></span><span class="pullDownLabel">下拉刷新</span>';
  29. scrollerObj.insertBefore(pullDownEl, scrollerObj.firstChild);
  30. pullDownOffset = pullDownEl.offsetHeight;
  31. }
  32. if (pullUpActionHandler) {
  33. // If a pullUpActionHandler-function is supplied, add a pull-up bar in the bottom and enable pull-up-to-load.
  34. // (if pullUpActionHandler==null this iScroll will have no pull-up-functionality)
  35. pullUpEl=document.createElement('div');
  36. pullUpEl.className='pullUp';
  37. pullUpEl.innerHTML='<span class="pullUpIcon"></span><span class="pullUpLabel">上拉加载更多</span>';
  38. scrollerObj.appendChild(pullUpEl);
  39. }
  40. // TODO 尝试解决 华为P10等多款手机型号上下滑动的页面都会卡顿现象,比如管理员端的所有界面,以及代预约的页面问题
  41. iScrollConfig = iScrollConfig || {}
  42. iScrollConfig.disablePointer = true
  43. iScrollConfig.disableTouch = false
  44. iScrollConfig.disableMouse = false
  45. me.myScroll = new IScroll(wrapperObj,iScrollConfig);
  46. me.myScroll.on('refresh',function() {
  47. if ((pullDownEl)&&(pullDownEl.className.match('loading'))) {
  48. pullDownEl.querySelector('.pullDownLabel').innerHTML = '下拉刷新';
  49. if (this.y>=0) {
  50. // The pull-down-bar is fully visible:
  51. // Hide it with a simple 250ms animation
  52. hidePullDownEl(250,true);
  53. } else if (this.y>-pullDownOffset) {
  54. // The pull-down-bar is PARTLY visible:
  55. // Set up a shorter animation to hide it
  56. // Firt calculate a new margin-top for pullDownEl that matches the current scroll position
  57. pullDownEl.style.marginTop=this.y+'px';
  58. // CSS-trick to force webkit to render/update any CSS-changes immediately: Access the offsetHeight property...
  59. pullDownEl.offsetHeight;
  60. // Calculate the animation time (shorter, dependant on the new distance to animate) from here to completely 'scrolledUp' (hidden)
  61. // Needs to be done before adjusting the scroll-positon (if we want to read this.y)
  62. var animTime=(250*(pullDownOffset+this.y)/pullDownOffset);
  63. // Set scroll positon to top
  64. // (this is the same as adjusting the scroll postition to match the exact movement pullDownEl made due to the change of margin-top above, so the content will not "jump")
  65. this.scrollTo(0,0,0);
  66. // Hide pullDownEl with the new (shorter) animation (and reset the inline style again).
  67. setTimeout(function() { // Do this in a new thread to avoid glitches in iOS webkit (will make sure the immediate margin-top change above is rendered)...
  68. hidePullDownEl(animTime,true);
  69. },0);
  70. } else {
  71. // The pull-down-bar is completely off screen:
  72. // Hide it immediately
  73. hidePullDownEl(0,true);
  74. // And adjust the scroll postition to match the exact movement pullDownEl made due to change of margin-top above, so the content will not "jump"
  75. this.scrollBy(0,pullDownOffset,0);
  76. }
  77. }
  78. if ((pullUpEl)&&(pullUpEl.className.match('loading'))) {
  79. pullUpEl.className = 'pullUp';
  80. pullUpEl.querySelector('.pullUpLabel').innerHTML = '上拉加载更多';
  81. }
  82. });
  83. me.myScroll.on('scrollStart',function() {
  84. scrollStartPos=this.y; // Store the scroll starting point to be able to track movement in 'scroll' below
  85. });
  86. me.myScroll.on('scroll',function() {
  87. if (pullDownEl||pullUpEl) {
  88. if((scrollStartPos==0)&&(this.y==0)) {
  89. // 'scroll' called, but scroller is not moving!
  90. // Probably because the content inside wrapper is small and fits the screen, so drag/scroll is disabled by iScroll
  91. // Fix this by a hack: Setting "myScroll.hasVerticalScroll=true" tricks iScroll to believe
  92. // that there is a vertical scrollbar, and iScroll will enable dragging/scrolling again...
  93. this.hasVerticalScroll=true;
  94. // Set scrollStartPos to -1000 to be able to detect this state later...
  95. scrollStartPos=-1000;
  96. } else if ((scrollStartPos==-1000) &&
  97. (((!pullUpEl)&&(!pullDownEl.className.match('flip'))&&(this.y<0)) ||
  98. ((!pullDownEl)&&(!pullUpEl.className.match('flip'))&&(this.y>0)))) {
  99. // Scroller was not moving at first (and the trick above was applied), but now it's moving in the wrong direction.
  100. // I.e. the user is either scrolling up while having no "pull-up-bar",
  101. // or scrolling down while having no "pull-down-bar" => Disable the trick again and reset values...
  102. this.hasVerticalScroll=false;
  103. scrollStartPos=0;
  104. this.scrollBy(0,-this.y, 0); // Adjust scrolling position to undo this "invalid" movement
  105. }
  106. }
  107. if (pullDownEl) {
  108. if (this.y > pullDownOffset+pullThreshold && !pullDownEl.className.match('flip')) {
  109. showPullDownElNow('flip');
  110. this.scrollBy(0,-pullDownOffset, 0); // Adjust scrolling position to match the change in pullDownEl's margin-top
  111. pullDownEl.querySelector('.pullDownLabel').innerHTML = '刷新数据中...';
  112. } else if (this.y < 0 && pullDownEl.className.match('flip')) { // User changes his mind...
  113. hidePullDownEl(0,false);
  114. this.scrollBy(0,pullDownOffset, 0); // Adjust scrolling position to match the change in pullDownEl's margin-top
  115. pullDownEl.querySelector('.pullDownLabel').innerHTML = '下拉刷新';
  116. }
  117. }
  118. if (pullUpEl) {
  119. if (this.y < (this.maxScrollY - pullThreshold) && !pullUpEl.className.match('flip')) {
  120. pullUpEl.className = 'pullUp flip';
  121. pullUpEl.querySelector('.pullUpLabel').innerHTML = '正在加载...';
  122. } else if (this.y > (this.maxScrollY + pullThreshold) && pullUpEl.className.match('flip')) {
  123. pullUpEl.className = 'pullUp';
  124. pullUpEl.querySelector('.pullUpLabel').innerHTML = '上拉加载更多';
  125. }
  126. }
  127. });
  128. me.myScroll.on('scrollEnd',function() {
  129. if ((pullDownEl)&&(pullDownEl.className.match('flip'))) {
  130. showPullDownElNow('loading');
  131. pullDownEl.querySelector('.pullDownLabel').innerHTML = '刷新数据中...';
  132. pullDownActionHandler(this); // Execute custom function (ajax call?)
  133. }
  134. if ((pullUpEl)&&(pullUpEl.className.match('flip'))) {
  135. pullUpEl.className = 'pullUp loading';
  136. pullUpEl.querySelector('.pullUpLabel').innerHTML = '正在加载...';
  137. pullUpActionHandler(this); // Execute custom function (ajax call?)
  138. }
  139. if (scrollStartPos=-1000) {
  140. // If scrollStartPos=-1000: Recalculate the true value of "hasVerticalScroll" as it may have been
  141. // altered in 'scroll' to enable pull-to-refresh/load when the content fits the screen...
  142. this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0;
  143. }
  144. });
  145. }
  146. // window.addEventListener('load', function() {init()}, false);
  147. init();
  148. return me.myScroll;
  149. };