z-paging-wxs.wxs 10.0 KB

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