nvue.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. // [z-paging]nvue独有部分模块
  2. import u from '.././z-paging-utils'
  3. import c from '.././z-paging-constant'
  4. import Enum from '.././z-paging-enum'
  5. // #ifdef APP-NVUE
  6. const weexAnimation = weex.requireModule('animation');
  7. // #endif
  8. export default {
  9. props: {
  10. // #ifdef APP-NVUE
  11. // nvue中修改列表类型,可选值有list、waterfall和scroller,默认为list
  12. nvueListIs: {
  13. type: String,
  14. default: u.gc('nvueListIs', 'list')
  15. },
  16. // nvue waterfall配置,仅在nvue中且nvueListIs=waterfall时有效,配置参数详情参见:https://uniapp.dcloud.io/component/waterfall
  17. nvueWaterfallConfig: {
  18. type: Object,
  19. default: u.gc('nvueWaterfallConfig', {})
  20. },
  21. // nvue 控制是否回弹效果,iOS不支持动态修改
  22. nvueBounce: {
  23. type: Boolean,
  24. default: u.gc('nvueBounce', true)
  25. },
  26. // nvue中通过代码滚动到顶部/底部时,是否加快动画效果(无滚动动画时无效),默认为否
  27. nvueFastScroll: {
  28. type: Boolean,
  29. default: u.gc('nvueFastScroll', false)
  30. },
  31. // nvue中list的id
  32. nvueListId: {
  33. type: String,
  34. default: u.gc('nvueListId', '')
  35. },
  36. // nvue中refresh组件的样式
  37. nvueRefresherStyle: {
  38. type: Object,
  39. default: u.gc('nvueRefresherStyle', {})
  40. },
  41. // nvue中是否按分页模式(类似竖向swiper)显示List,默认为false
  42. nvuePagingEnabled: {
  43. type: Boolean,
  44. default: u.gc('nvuePagingEnabled', false)
  45. },
  46. // 是否隐藏nvue列表底部的tagView,此view用于标识滚动到底部位置,若隐藏则滚动到底部功能将失效,在nvue中实现吸顶+swiper功能时需将最外层z-paging的此属性设置为true。默认为否
  47. hideNvueBottomTag: {
  48. type: Boolean,
  49. default: u.gc('hideNvueBottomTag', false)
  50. },
  51. // nvue中控制onscroll事件触发的频率:表示两次onscroll事件之间列表至少滚动了10px。注意,将该值设置为较小的数值会提高滚动事件采样的精度,但同时也会降低页面的性能
  52. offsetAccuracy: {
  53. type: Number,
  54. default: u.gc('offsetAccuracy', 10)
  55. },
  56. // #endif
  57. },
  58. data() {
  59. return {
  60. nRefresherLoading: false,
  61. nListIsDragging: false,
  62. nShowBottom: true,
  63. nFixFreezing: false,
  64. nShowRefresherReveal: false,
  65. nLoadingMoreFixedHeight: false,
  66. nShowRefresherRevealHeight: 0,
  67. nOldShowRefresherRevealHeight: -1,
  68. nRefresherWidth: uni.upx2px(750),
  69. nF2Opacity: 0
  70. }
  71. },
  72. computed: {
  73. // #ifdef APP-NVUE
  74. nScopedSlots() {
  75. // #ifdef VUE2
  76. return this.$scopedSlots;
  77. // #endif
  78. // #ifdef VUE3
  79. return null;
  80. // #endif
  81. },
  82. nWaterfallColumnCount() {
  83. if (this.finalNvueListIs !== 'waterfall') return 0;
  84. return this._nGetWaterfallConfig('column-count', 2);
  85. },
  86. nWaterfallColumnWidth() {
  87. return this._nGetWaterfallConfig('column-width', 'auto');
  88. },
  89. nWaterfallColumnGap() {
  90. return this._nGetWaterfallConfig('column-gap', 'normal');
  91. },
  92. nWaterfallLeftGap() {
  93. return this._nGetWaterfallConfig('left-gap', 0);
  94. },
  95. nWaterfallRightGap() {
  96. return this._nGetWaterfallConfig('right-gap', 0);
  97. },
  98. nViewIs() {
  99. const is = this.finalNvueListIs;
  100. return is === 'scroller' || is === 'view' ? 'view' : is === 'waterfall' ? 'header' : 'cell';
  101. },
  102. nSafeAreaBottomHeight() {
  103. return this.safeAreaInsetBottom ? this.safeAreaBottom : 0;
  104. },
  105. finalNvueListIs() {
  106. if (this.usePageScroll) return 'view';
  107. const nvueListIsLowerCase = this.nvueListIs.toLowerCase();
  108. if (['list','waterfall','scroller'].indexOf(nvueListIsLowerCase) !== -1) return nvueListIsLowerCase;
  109. return 'list';
  110. },
  111. finalNvueSuperListIs() {
  112. return this.usePageScroll ? 'view' : 'scroller';
  113. },
  114. finalNvueRefresherEnabled() {
  115. return this.finalNvueListIs !== 'view' && this.finalRefresherEnabled && !this.nShowRefresherReveal && !this.useChatRecordMode;
  116. },
  117. // #endif
  118. },
  119. mounted(){
  120. // #ifdef APP-NVUE
  121. //旋转屏幕时更新宽度
  122. uni.onWindowResize((res) => {
  123. // this._nUpdateRefresherWidth();
  124. })
  125. // #endif
  126. },
  127. methods: {
  128. // #ifdef APP-NVUE
  129. // 列表滚动时触发
  130. _nOnScroll(e) {
  131. this.$emit('scroll', e);
  132. const contentOffsetY = -e.contentOffset.y;
  133. this.oldScrollTop = contentOffsetY;
  134. this.nListIsDragging = e.isDragging;
  135. this._checkShouldShowBackToTop(contentOffsetY, contentOffsetY - 1);
  136. },
  137. // 列表滚动结束
  138. _nOnScrollend(e) {
  139. this.$emit('scrollend', e);
  140. },
  141. // 下拉刷新刷新中
  142. _nOnRrefresh() {
  143. if (this.nShowRefresherReveal) return;
  144. // 进入刷新状态
  145. this.nRefresherLoading = true;
  146. if (this.refresherStatus === Enum.Refresher.GoF2) {
  147. this._handleGoF2();
  148. this.$nextTick(() => {
  149. this._nRefresherEnd();
  150. })
  151. } else {
  152. this.refresherStatus = Enum.Refresher.Loading;
  153. this._doRefresherLoad();
  154. }
  155. },
  156. // 下拉刷新下拉中
  157. _nOnPullingdown(e) {
  158. if (this.refresherStatus === Enum.Refresher.Loading || (this.isIos && !this.nListIsDragging)) return;
  159. this._emitTouchmove(e);
  160. let { viewHeight, pullingDistance } = e;
  161. // 更新下拉刷新状态
  162. // 下拉刷新距离超过阈值
  163. if (pullingDistance >= viewHeight) {
  164. // 如果开启了下拉进入二楼并且下拉刷新距离超过进入二楼阈值,则当前下拉刷新状态为松手进入二楼,否则为松手立即刷新
  165. // (pullingDistance - viewHeight) + this.finalRefresherThreshold 不等同于pullingDistance,此处是为了兼容不同平台下拉相同距离pullingDistance不一致的问题,pullingDistance仅与viewHeight互相关联
  166. this.refresherStatus = this.refresherF2Enabled && (pullingDistance - viewHeight) + this.finalRefresherThreshold >= this.finalRefresherF2Threshold ? Enum.Refresher.GoF2 : Enum.Refresher.ReleaseToRefresh;
  167. } else {
  168. // 下拉刷新距离未超过阈值,显示默认状态
  169. this.refresherStatus = Enum.Refresher.Default;
  170. }
  171. },
  172. // 下拉刷新结束
  173. _nRefresherEnd(doEnd = true) {
  174. if (doEnd) {
  175. this._nDoRefresherEndAnimation(0, -this.nShowRefresherRevealHeight);
  176. !this.usePageScroll && this.$refs['zp-n-list'].resetLoadmore();
  177. this.nRefresherLoading = false;
  178. }
  179. },
  180. // 执行主动触发下拉刷新动画
  181. _nDoRefresherEndAnimation(height, translateY, animate = true, checkStack = true) {
  182. // 清除下拉刷新相关timeout
  183. this._cleanRefresherCompleteTimeout();
  184. this._cleanRefresherEndTimeout();
  185. if (!this.finalShowRefresherWhenReload) {
  186. // 如果reload不需要自动展示下拉刷新view,则在complete duration结束后再把下拉刷新状态设置回默认
  187. this.refresherEndTimeout = u.delay(() => {
  188. this.refresherStatus = Enum.Refresher.Default;
  189. }, this.refresherCompleteDuration);
  190. return;
  191. }
  192. // 用户处理用户在短时间内多次调用reload的情况,此时下拉刷新view不需要重复显示,只需要保证最后一次reload对应的请求结束后收回下拉刷新view即可
  193. const stackCount = this.refresherRevealStackCount;
  194. if (height === 0 && checkStack) {
  195. this.refresherRevealStackCount --;
  196. if (stackCount > 1) return;
  197. this.refresherEndTimeout = u.delay(() => {
  198. this.refresherStatus = Enum.Refresher.Default;
  199. }, this.refresherCompleteDuration);
  200. }
  201. if (stackCount > 1) {
  202. this.refresherStatus = Enum.Refresher.Loading;
  203. }
  204. const duration = animate ? 200 : 0;
  205. if (this.nOldShowRefresherRevealHeight !== height) {
  206. if (height > 0) {
  207. this.nShowRefresherReveal = true;
  208. }
  209. // 展示下拉刷新view
  210. weexAnimation.transition(this.$refs['zp-n-list-refresher-reveal'], {
  211. styles: {
  212. height: `${height}px`,
  213. transform: `translateY(${translateY}px)`,
  214. },
  215. duration,
  216. timingFunction: 'linear',
  217. needLayout: true,
  218. delay: 0
  219. })
  220. }
  221. u.delay(() => {
  222. if (animate) {
  223. this.nShowRefresherReveal = height > 0;
  224. }
  225. }, duration > 0 ? duration - 60 : 0);
  226. this.nOldShowRefresherRevealHeight = height;
  227. },
  228. // 滚动到底部加载更多
  229. _nOnLoadmore() {
  230. if (this.nShowRefresherReveal || !this.totalData.length) return;
  231. this.useChatRecordMode ? this.doChatRecordLoadMore() : this._onLoadingMore('toBottom');
  232. },
  233. // 获取nvue waterfall单项配置
  234. _nGetWaterfallConfig(key, defaultValue) {
  235. return this.nvueWaterfallConfig[key] || defaultValue;
  236. },
  237. // 更新nvue 下拉刷新view容器的宽度
  238. _nUpdateRefresherWidth() {
  239. u.delay(() => {
  240. this.$nextTick(()=>{
  241. this._getNodeClientRect('.zp-n-list').then(node => {
  242. if (node) {
  243. this.nRefresherWidth = node[0].width || this.nRefresherWidth;
  244. }
  245. })
  246. })
  247. })
  248. }
  249. // #endif
  250. }
  251. }