z-paging-wxs.wxs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. // [z-paging]微信小程序、QQ小程序、app-vue、h5上使用wxs实现自定义下拉刷新,降低逻辑层与视图层的通信折损,提升性能
  2. var currentDis = 0;
  3. var isPCFlag = -1;
  4. var startY = -1;
  5. function propObserver(newValue, oldValue, ownerIns, ins) {
  6. var state = ownerIns.getState() || {};
  7. state.currentIns = ins;
  8. var dataset = ins.getDataset();
  9. var loading = dataset.loading == true;
  10. if (newValue && newValue.indexOf('end') != -1) {
  11. var transition = newValue.split('end')[0];
  12. _setTransform('translateY(0px)', ins, false, transition);
  13. state.moveDis = 0;
  14. state.oldMoveDis = 0;
  15. currentDis = 0;
  16. } else if (newValue && newValue.indexOf('begin') != -1) {
  17. var refresherThreshold = ins.getDataset().refresherthreshold;
  18. _setTransformValue(refresherThreshold, ins, state, false);
  19. }
  20. }
  21. function touchstart(e, ownerIns) {
  22. var ins = _getIns(ownerIns);
  23. var state = {};
  24. var dataset = {};
  25. ownerIns.callMethod('_handleListTouchstart');
  26. if (ins) {
  27. state = ins.getState();
  28. dataset = ins.getDataset();
  29. if (_touchDisabled(e, ins, 0)) return;
  30. }
  31. var isTouchEnded = state.isTouchEnded;
  32. state.oldMoveDis = 0;
  33. var touch = _getTouch(e);
  34. var loading = _getIsTrue(dataset.loading);
  35. state.startY = touch.touchY;
  36. startY = state.startY;
  37. state.lastTouch = touch;
  38. if (!loading && isTouchEnded) {
  39. state.isTouchmoving = false;
  40. }
  41. state.isTouchEnded = false;
  42. ownerIns.callMethod('_handleRefresherTouchstart', touch);
  43. }
  44. function touchmove(e, ownerIns) {
  45. var touch = _getTouch(e);
  46. var ins = _getIns(ownerIns);
  47. var dataset = ins.getDataset();
  48. var refresherThreshold = dataset.refresherthreshold;
  49. var isIos = _getIsTrue(dataset.isios);
  50. var state = ins.getState();
  51. var dataset = ins.getDataset();
  52. var watchTouchDirectionChange = _getIsTrue(dataset.watchtouchdirectionchange);
  53. var moveDisObj = {};
  54. var moveDis = 0;
  55. var prevent = false;
  56. if (watchTouchDirectionChange) {
  57. moveDisObj = _getMoveDis(e, ins);
  58. moveDis = moveDisObj.currentDis;
  59. prevent = moveDisObj.isDown;
  60. if(state.oldAcceptedIsDown == prevent){
  61. ownerIns.callMethod('_handleTouchDirectionChange', {direction: prevent ? 'top' : 'bottom'});
  62. state.oldIsDown = prevent;
  63. }
  64. state.oldAcceptedIsDown = prevent;
  65. }
  66. if (_touchDisabled(e, ins, 1)) {
  67. _handlePullingDown(state, ownerIns, false);
  68. return true;
  69. }
  70. if (!_getAngleIsInRange(e, touch, state, dataset)) {
  71. _handlePullingDown(state, ownerIns, false);
  72. return true;
  73. }
  74. moveDisObj = _getMoveDis(e, ins);
  75. moveDis = moveDisObj.currentDis;
  76. prevent = moveDisObj.isDown;
  77. if (moveDis < 0) {
  78. _setTransformValue(0, ins, state, false);
  79. _handlePullingDown(state, ownerIns, false);
  80. return true;
  81. }
  82. if (prevent && !state.disabledBounce) {
  83. if (isIos) {
  84. ownerIns.callMethod('_handleScrollViewDisableBounce', {bounce: false});
  85. }
  86. state.disabledBounce = true;
  87. _handlePullingDown(state, ownerIns, prevent);
  88. return !prevent;
  89. }
  90. _setTransformValue(moveDis, ins, state, false);
  91. var oldRefresherStatus = state.refresherStatus;
  92. var oldIsTouchmoving = _getIsTrue(dataset.oldistouchmoving);
  93. var hasTouchmove = _getIsTrue(dataset.hastouchmove);
  94. var isTouchmoving = state.isTouchmoving;
  95. state.refresherStatus = moveDis >= refresherThreshold ? 1 : 0;
  96. if (!isTouchmoving) {
  97. state.isTouchmoving = true;
  98. isTouchmoving = true;
  99. }
  100. if (state.isTouchEnded) {
  101. state.isTouchEnded = false;
  102. }
  103. if (hasTouchmove) {
  104. ownerIns.callMethod('_handleWxsPullingDown', {moveDis:moveDis, diffDis:moveDisObj.diffDis});
  105. }
  106. if (oldRefresherStatus == undefined || oldRefresherStatus != state.refresherStatus || oldIsTouchmoving != isTouchmoving) {
  107. ownerIns.callMethod('_handleRefresherTouchmove', moveDis, touch);
  108. }
  109. _handlePullingDown(state, ownerIns, prevent);
  110. return !prevent;
  111. }
  112. function touchend(e, ownerIns) {
  113. var touch = _getTouch(e);
  114. var ins = _getIns(ownerIns);
  115. var dataset = ins.getDataset();
  116. var state = ins.getState();
  117. if (_touchDisabled(e, ins, 2)) return;
  118. state.reachMaxAngle = true;
  119. state.hitReachMaxAngleCount = 0;
  120. state.disabledBounce = false;
  121. state.fixedIsTopHitCount = 0;
  122. //ownerIns.callMethod('_handleScrollViewDisableBounce', {bounce:true});
  123. if (!state.isTouchmoving) return;
  124. var oldRefresherStatus = state.refresherStatus;
  125. var oldMoveDis = state.moveDis;
  126. var refresherThreshold = ins.getDataset().refresherthreshold
  127. var moveDis = _getMoveDis(e, ins).currentDis;
  128. if (!(moveDis >= refresherThreshold && oldRefresherStatus === 1)) {
  129. state.isTouchmoving = false;
  130. }
  131. ownerIns.callMethod('_handleRefresherTouchend', moveDis);
  132. state.isTouchEnded = true;
  133. if (oldMoveDis < refresherThreshold) return;
  134. var animate = false;
  135. if (moveDis >= refresherThreshold) {
  136. moveDis = refresherThreshold;
  137. animate = true;
  138. }
  139. _setTransformValue(moveDis, ins, state, animate);
  140. }
  141. // #ifdef H5
  142. function isPC() {
  143. if (!navigator) return false;
  144. if (isPCFlag != -1) return isPCFlag;
  145. var userAgentInfo = navigator.userAgent;
  146. var Agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
  147. var flag = true;
  148. for (var i = 0; i < Agents.length; i++) {
  149. if (userAgentInfo.indexOf(Agents[i]) > 0) {
  150. flag = false;
  151. break;
  152. }
  153. }
  154. isPCFlag = flag;
  155. return isPCFlag;
  156. }
  157. var movable = false;
  158. function mousedown(e, ins) {
  159. if (!isPC()) return;
  160. touchstart(e, ins);
  161. movable = true;
  162. }
  163. function mousemove(e, ins) {
  164. if (!isPC()) return;
  165. if (!movable) return;
  166. touchmove(e, ins);
  167. }
  168. function mouseup(e, ins) {
  169. if (!isPC()) return;
  170. touchend(e, ins);
  171. movable = false;
  172. }
  173. function mouseleave(e, ins) {
  174. if (!isPC()) return;
  175. movable = false;
  176. }
  177. // #endif
  178. function _setTransformValue(value, ins, state, animate) {
  179. value = value || 0;
  180. if (state.moveDis == value) return;
  181. state.moveDis = value;
  182. _setTransform('translateY(' + value + 'px)', ins, animate, '');
  183. }
  184. function _setTransform(transform, ins, animate, transition) {
  185. if (transform == 'translateY(0px)') {
  186. transform = 'none';
  187. }
  188. ins.requestAnimationFrame(function() {
  189. var stl = { 'transform': transform };
  190. if (animate) {
  191. stl['transition'] = 'transform .1s linear';
  192. }
  193. if (transition.length) {
  194. stl['transition'] = transition;
  195. }
  196. ins.setStyle(stl);
  197. })
  198. }
  199. function _getMoveDis(e, ins) {
  200. var state = ins.getState();
  201. var refresherThreshold = parseFloat(ins.getDataset().refresherthreshold);
  202. var refresherOutRate = parseFloat(ins.getDataset().refresheroutrate);
  203. var touch = _getTouch(e);
  204. var currentStartY = !state.startY || state.startY == 'NaN' ? startY : state.startY;
  205. var moveDis = touch.touchY - currentStartY;
  206. var oldMoveDis = state.oldMoveDis || 0;
  207. state.oldMoveDis = moveDis;
  208. var diffDis = moveDis - oldMoveDis;
  209. if (diffDis > 0) {
  210. diffDis = diffDis * 0.85;
  211. if (currentDis > refresherThreshold) {
  212. diffDis = diffDis * (1 - refresherOutRate);
  213. }
  214. }
  215. if (diffDis > 200) {
  216. currentDis = 0;
  217. diffDis = 0;
  218. } else {
  219. currentDis += diffDis;
  220. currentDis = Math.max(0, currentDis);
  221. }
  222. return {
  223. currentDis: currentDis,
  224. diffDis: diffDis,
  225. isDown: diffDis > 0
  226. };
  227. }
  228. function _getTouch(e) {
  229. var touch = e;
  230. if (e.touches && e.touches.length) {
  231. touch = e.touches[0];
  232. } else if (e.changedTouches && e.changedTouches.length) {
  233. touch = e.changedTouches[0];
  234. } else if (e.datail && e.datail != {}) {
  235. touch = e.datail;
  236. }
  237. return {
  238. touchX: touch.clientX,
  239. touchY: touch.clientY
  240. };
  241. }
  242. function _getIns(ownerIns) {
  243. var ins = ownerIns.getState().currentIns;
  244. if (!ins) {
  245. ownerIns.callMethod('_handlePropUpdate');
  246. }
  247. return ins;
  248. }
  249. function _touchDisabled(e, ins, processTag) {
  250. var dataset = ins.getDataset();
  251. var state = ins.getState();
  252. var loading = _getIsTrue(dataset.loading);
  253. var useChatRecordMode = _getIsTrue(dataset.usechatrecordmode);
  254. var refresherEnabled = _getIsTrue(dataset.refresherenabled);
  255. var useCustomRefresher = _getIsTrue(dataset.usecustomrefresher);
  256. var usePageScroll = _getIsTrue(dataset.usepagescroll);
  257. var pageScrollTop = parseFloat(dataset.pagescrolltop);
  258. var scrollTop = parseFloat(dataset.scrolltop);
  259. var finalScrollTop = usePageScroll ? pageScrollTop : scrollTop;
  260. var fixedIsTop = false;
  261. var isIos = _getIsTrue(dataset.isios);
  262. if (!isIos && finalScrollTop == (state.startScrollTop || 0) && finalScrollTop <= 105) {
  263. fixedIsTop = true;
  264. }
  265. var fixedIsTopHitCount = state.fixedIsTopHitCount || 0;
  266. if (fixedIsTop) {
  267. fixedIsTopHitCount++;
  268. if (fixedIsTopHitCount <= 3) {
  269. fixedIsTop = false;
  270. }
  271. state.fixedIsTopHitCount = fixedIsTopHitCount;
  272. } else {
  273. state.fixedIsTopHitCount = 0;
  274. }
  275. if (!isIos && processTag === 0) {
  276. state.startScrollTop = finalScrollTop || 0;
  277. }
  278. if (!isIos && processTag === 2) {
  279. fixedIsTop = true;
  280. }
  281. var res = loading || useChatRecordMode || !refresherEnabled || !useCustomRefresher || ((usePageScroll && useCustomRefresher && pageScrollTop > 5) && !fixedIsTop) ||
  282. ((!usePageScroll && useCustomRefresher && scrollTop > 5) && !fixedIsTop);
  283. return res;
  284. }
  285. function _getAngleIsInRange(e, touch, state, dataset) {
  286. var maxAngle = dataset.refreshermaxangle;
  287. var refresherAecc = _getIsTrue(dataset.refresheraecc);
  288. var lastTouch = state.lastTouch;
  289. var reachMaxAngle = state.reachMaxAngle;
  290. var moveDis = state.oldMoveDis;
  291. if (!lastTouch) return true;
  292. if (maxAngle >= 0 && maxAngle <= 90 && lastTouch) {
  293. if ((!moveDis || moveDis < 1) && !refresherAecc && reachMaxAngle != null && !reachMaxAngle) return false;
  294. var x = Math.abs(touch.touchX - lastTouch.touchX);
  295. var y = Math.abs(touch.touchY - lastTouch.touchY);
  296. var z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
  297. if ((x || y) && x > 1) {
  298. var angle = Math.asin(y / z) / Math.PI * 180;
  299. if (angle < maxAngle) {
  300. var hitReachMaxAngleCount = state.hitReachMaxAngleCount || 0;
  301. state.hitReachMaxAngleCount = ++hitReachMaxAngleCount;
  302. if (state.hitReachMaxAngleCount > 2) {
  303. state.lastTouch = touch;
  304. state.reachMaxAngle = false;
  305. }
  306. return false;
  307. }
  308. }
  309. }
  310. state.lastTouch = touch;
  311. return true;
  312. }
  313. function _handlePullingDown(state, ins, onPullingDown) {
  314. var oldOnPullingDown = state.onPullingDown || false;
  315. if (oldOnPullingDown != onPullingDown) {
  316. ins.callMethod('_handleWxsPullingDownStatusChange', onPullingDown);
  317. }
  318. state.onPullingDown = onPullingDown;
  319. }
  320. function _getIsTrue(value) {
  321. value = (typeof(value) === 'string' ? JSON.parse(value) : value) || false;
  322. return value == true || value == 'true';
  323. }
  324. module.exports = {
  325. touchstart: touchstart,
  326. touchmove: touchmove,
  327. touchend: touchend,
  328. mousedown: mousedown,
  329. mousemove: mousemove,
  330. mouseup: mouseup,
  331. mouseleave: mouseleave,
  332. propObserver: propObserver
  333. }