data-handle.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. // [z-paging]数据处理模块
  2. import u from '.././z-paging-utils'
  3. import c from '.././z-paging-constant'
  4. import Enum from '.././z-paging-enum'
  5. import interceptor from '../z-paging-interceptor'
  6. export default {
  7. props: {
  8. //自定义初始的pageNo,默认为1
  9. defaultPageNo: {
  10. type: [Number, String],
  11. default: u.gc('defaultPageNo', 1),
  12. observer: function(newVal) {
  13. this.pageNo = newVal;
  14. },
  15. },
  16. //自定义pageSize,默认为10
  17. defaultPageSize: {
  18. type: [Number, String],
  19. default: u.gc('defaultPageSize', 10),
  20. validator: (value) => {
  21. if(value <= 0) u.consoleErr('default-page-size必须大于0!');
  22. return value > 0;
  23. }
  24. },
  25. //为保证数据一致,设置当前tab切换时的标识key,并在complete中传递相同key,若二者不一致,则complete将不会生效
  26. dataKey: {
  27. type: [Number, String, Object],
  28. default: function() {
  29. return u.gc('dataKey', null);
  30. },
  31. },
  32. //使用缓存,若开启将自动缓存第一页的数据,默认为否。请注意,因考虑到切换tab时不同tab数据不同的情况,默认仅会缓存组件首次加载时第一次请求到的数据,后续的下拉刷新操作不会更新缓存。
  33. useCache: {
  34. type: Boolean,
  35. default: u.gc('useCache', false)
  36. },
  37. //使用缓存时缓存的key,用于区分不同列表的缓存数据,useCache为true时必须设置,否则缓存无效
  38. cacheKey: {
  39. type: String,
  40. default: u.gc('cacheKey', null)
  41. },
  42. //缓存模式,默认仅会缓存组件首次加载时第一次请求到的数据,可设置为always,即代表总是缓存,每次列表刷新(下拉刷新、调用reload等)都会更新缓存
  43. cacheMode: {
  44. type: String,
  45. default: u.gc('cacheMode', Enum.CacheMode.Default)
  46. },
  47. //自动注入的list名,可自动修改父view(包含ref="paging")中对应name的list值
  48. autowireListName: {
  49. type: String,
  50. default: u.gc('autowireListName', '')
  51. },
  52. //自动注入的query名,可自动调用父view(包含ref="paging")中的query方法
  53. autowireQueryName: {
  54. type: String,
  55. default: u.gc('autowireQueryName', '')
  56. },
  57. //z-paging mounted后自动调用reload方法(mounted后自动调用接口),默认为是
  58. auto: {
  59. type: Boolean,
  60. default: u.gc('auto', true)
  61. },
  62. //用户下拉刷新时是否触发reload方法,默认为是
  63. reloadWhenRefresh: {
  64. type: Boolean,
  65. default: u.gc('reloadWhenRefresh', true)
  66. },
  67. //reload时自动滚动到顶部,默认为是
  68. autoScrollToTopWhenReload: {
  69. type: Boolean,
  70. default: u.gc('autoScrollToTopWhenReload', true)
  71. },
  72. //reload时立即自动清空原list,默认为是,若立即自动清空,则在reload之后、请求回调之前页面是空白的
  73. autoCleanListWhenReload: {
  74. type: Boolean,
  75. default: u.gc('autoCleanListWhenReload', true)
  76. },
  77. //列表刷新时自动显示下拉刷新view,默认为否
  78. showRefresherWhenReload: {
  79. type: Boolean,
  80. default: u.gc('showRefresherWhenReload', false)
  81. },
  82. //列表刷新时自动显示加载更多view,且为加载中状态,默认为否
  83. showLoadingMoreWhenReload: {
  84. type: Boolean,
  85. default: u.gc('showLoadingMoreWhenReload', false)
  86. },
  87. //组件created时立即触发reload(可解决一些情况下先看到页面再看到loading的问题),auto为true时有效。为否时将在mounted+nextTick后触发reload,默认为否
  88. createdReload: {
  89. type: Boolean,
  90. default: u.gc('createdReload', false)
  91. },
  92. //本地分页时上拉加载更多延迟时间,单位为毫秒,默认200毫秒
  93. localPagingLoadingTime: {
  94. type: [Number, String],
  95. default: u.gc('localPagingLoadingTime', 200)
  96. },
  97. //使用聊天记录模式,默认为否
  98. useChatRecordMode: {
  99. type: Boolean,
  100. default: u.gc('useChatRecordMode', false)
  101. },
  102. //使用聊天记录模式时是否自动隐藏键盘:在用户触摸列表时候自动隐藏键盘,默认为是
  103. autoHideKeyboardWhenChat: {
  104. type: Boolean,
  105. default: u.gc('autoHideKeyboardWhenChat', true)
  106. },
  107. //自动拼接complete中传过来的数组(使用聊天记录模式时无效)
  108. concat: {
  109. type: Boolean,
  110. default: u.gc('concat', true)
  111. },
  112. //父组件v-model所绑定的list的值
  113. value: {
  114. type: Array,
  115. default: function() {
  116. return [];
  117. }
  118. },
  119. // #ifdef VUE3
  120. modelValue: {
  121. type: Array,
  122. default: function() {
  123. return [];
  124. }
  125. }
  126. // #endif
  127. },
  128. data (){
  129. return {
  130. currentData: [],
  131. totalData: [],
  132. realTotalData: [],
  133. totalLocalPagingList: [],
  134. isSettingCacheList: false,
  135. pageNo: 1,
  136. currentRefreshPageSize: 0,
  137. isLocalPaging: false,
  138. isAddedData: false,
  139. isTotalChangeFromAddData: false,
  140. privateConcat: true,
  141. myParentQuery: -1,
  142. firstPageLoaded: false,
  143. pagingLoaded: false,
  144. loaded: false,
  145. isUserReload: true,
  146. fromEmptyViewReload: false,
  147. queryFrom: '',
  148. listRendering: false,
  149. listRenderingTimeout: null
  150. }
  151. },
  152. computed: {
  153. pageSize() {
  154. return this.defaultPageSize;
  155. },
  156. finalConcat() {
  157. return this.concat && this.privateConcat;
  158. },
  159. finalUseCache() {
  160. if (this.useCache && !this.cacheKey) {
  161. u.consoleErr('use-cache为true时,必须设置cache-key,否则缓存无效!');
  162. }
  163. return this.useCache && !!this.cacheKey;
  164. },
  165. finalCacheKey() {
  166. if (!this.cacheKey) return null;
  167. return `${c.cachePrefixKey}-${this.cacheKey}`;
  168. },
  169. isFirstPage() {
  170. return this.pageNo === this.defaultPageNo;
  171. }
  172. },
  173. watch: {
  174. totalData(newVal, oldVal) {
  175. this._totalDataChange(newVal, oldVal);
  176. },
  177. currentData(newVal, oldVal) {
  178. this._currentDataChange(newVal, oldVal);
  179. },
  180. useChatRecordMode(newVal, oldVal) {
  181. if (newVal) {
  182. this.nLoadingMoreFixedHeight = false;
  183. }
  184. },
  185. value: {
  186. handler(newVal) {
  187. this.realTotalData = newVal;
  188. },
  189. immediate: true
  190. },
  191. // #ifdef VUE3
  192. modelValue: {
  193. handler(newVal) {
  194. this.realTotalData = newVal;
  195. },
  196. immediate: true
  197. }
  198. // #endif
  199. },
  200. methods: {
  201. //请求结束(成功或者失败)调用此方法,将请求的结果传递给z-paging处理,第一个参数为请求结果数组,第二个参数为是否成功(默认是是)
  202. complete(data, success = true) {
  203. this.customNoMore = -1;
  204. this.addData(data, success);
  205. },
  206. //简写,与complete完全相同
  207. end(data, success = true) {
  208. this.complete(data, success);
  209. },
  210. //【保证数据一致】请求结束(成功或者失败)调用此方法,将请求的结果传递给z-paging处理,第一个参数为请求结果数组,第二个参数为dataKey,需与:data-key绑定的一致,第三个参数为是否成功(默认为是)
  211. completeByKey(data, dataKey = null, success = true) {
  212. if (dataKey !== null && this.dataKey !== null && dataKey !== this.dataKey) {
  213. if (this.isFirstPage) {
  214. this.endRefresh();
  215. }
  216. return;
  217. }
  218. this.customNoMore = -1;
  219. this.addData(data, success);
  220. },
  221. //简写,与completeByKey完全相同
  222. endByKey(data, dataKey = null, success = true) {
  223. this.completeByKey(data, dataKey, success);
  224. },
  225. //【通过totalCount判断是否有更多数据】请求结束(成功或者失败)调用此方法,将请求的结果传递给z-paging处理,第一个参数为请求结果数组,第二个参数为totalCount(列表总数),第三个参数为是否成功(默认为是)
  226. completeByTotalCount(data, totalCount, success = true) {
  227. if (totalCount == 'undefined') {
  228. this.customNoMore = -1;
  229. } else {
  230. const dataTypeRes = this._checkDataType(data, success, false);
  231. data = dataTypeRes.data;
  232. success = dataTypeRes.success;
  233. if (totalCount >= 0 && success) {
  234. this.$nextTick(() => {
  235. let hasMore = true;
  236. let realTotalDataCount = this.realTotalData.length;
  237. if (this.pageNo == this.defaultPageNo) {
  238. realTotalDataCount = 0;
  239. }
  240. const dataLength = this.privateConcat ? data.length : 0;
  241. let exceedCount = realTotalDataCount + dataLength - totalCount;
  242. if (exceedCount >= 0) {
  243. hasMore = false;
  244. exceedCount = this.defaultPageSize - exceedCount;
  245. if (exceedCount > 0 && exceedCount < data.length && this.privateConcat) {
  246. data = data.splice(0, exceedCount);
  247. }
  248. }
  249. this.completeByNoMore(data, hasMore, success);
  250. })
  251. return;
  252. }
  253. }
  254. this.addData(data, success);
  255. },
  256. //简写,与completeByTotalCount完全相同
  257. completeByTotal(data, totalCount, success = true) {
  258. this.completeByTotalCount(data, totalCount, success);
  259. },
  260. //简写,与completeByTotalCount完全相同
  261. endByTotalCount(data, totalCount, success = true) {
  262. this.completeByTotalCount(data, totalCount, success);
  263. },
  264. //简写,与completeByTotalCount完全相同
  265. endByTotal(data, totalCount, success = true) {
  266. this.completeByTotalCount(data, totalCount, success);
  267. },
  268. //【自行判断是否有更多数据】请求结束(成功或者失败)调用此方法,将请求的结果传递给z-paging处理,第一个参数为请求结果数组,第二个参数为是否有更多数据,第三个参数为是否成功(默认是是)
  269. completeByNoMore(data, nomore, success = true) {
  270. if (nomore != 'undefined') {
  271. this.customNoMore = nomore == true ? 1 : 0;
  272. }
  273. this.addData(data, success);
  274. },
  275. //简写,与completeByNoMore完全相同
  276. endByNoMore(data, nomore, success = true) {
  277. this.completeByNoMore(data, nomore, success);
  278. },
  279. //与上方complete方法功能一致,新版本中设置服务端回调数组请使用complete方法
  280. addData(data, success = true) {
  281. if (!this.fromCompleteEmit) {
  282. this.disabledCompleteEmit = true;
  283. this.fromCompleteEmit = false;
  284. }
  285. const currentTimeStamp = u.getTime();
  286. let addDataDalay = 0;
  287. const disTime = currentTimeStamp - this.requestTimeStamp;
  288. let minDelay = this.minDelay;
  289. if(this.isFirstPage && this.finalShowRefresherWhenReload){
  290. minDelay = Math.max(400,minDelay);
  291. }
  292. if(this.requestTimeStamp > 0 && disTime < minDelay){
  293. addDataDalay = minDelay - disTime;
  294. }
  295. this.$nextTick(() => {
  296. let delay = this.delay > 0 ? this.delay : addDataDalay;
  297. setTimeout(() => {
  298. this._addData(data, success, false);
  299. }, delay)
  300. })
  301. },
  302. //从顶部添加数据,不会影响分页的pageNo和pageSize
  303. addDataFromTop(data, toTop = true, toTopWithAnimate = true) {
  304. let dataType = Object.prototype.toString.call(data);
  305. if (dataType !== '[object Array]') {
  306. data = [data];
  307. }
  308. this.totalData = [...data, ...this.totalData];
  309. if (toTop) {
  310. setTimeout(() => {
  311. this._scrollToTop(toTopWithAnimate);
  312. }, c.delayTime)
  313. }
  314. },
  315. //重新设置列表数据,调用此方法不会影响pageNo和pageSize,也不会触发请求。适用场景:当需要删除列表中某一项时,将删除对应项后的数组通过此方法传递给z-paging。(当出现类似的需要修改列表数组的场景时,请使用此方法,请勿直接修改page中:list.sync绑定的数组)
  316. resetTotalData(data) {
  317. this.isTotalChangeFromAddData = true;
  318. let dataType = Object.prototype.toString.call(data);
  319. if (dataType !== '[object Array]') {
  320. data = [data];
  321. }
  322. this.totalData = data;
  323. },
  324. //添加聊天记录
  325. addChatRecordData(data, toBottom = true, toBottomWithAnimate = true) {
  326. let dataType = Object.prototype.toString.call(data);
  327. if (dataType !== '[object Array]') {
  328. data = [data];
  329. }
  330. if (!this.useChatRecordMode) return;
  331. this.isTotalChangeFromAddData = true;
  332. //#ifndef APP-NVUE
  333. this.totalData = [...this.totalData, ...data];
  334. //#endif
  335. //#ifdef APP-NVUE
  336. this.totalData = this.nIsFirstPageAndNoMore ? [...this.totalData, ...data] : [...data, ...this.totalData];
  337. //#endif
  338. if (toBottom) {
  339. setTimeout(() => {
  340. //#ifndef APP-NVUE
  341. this._scrollToBottom(toBottomWithAnimate);
  342. //#endif
  343. //#ifdef APP-NVUE
  344. if (this.nIsFirstPageAndNoMore) {
  345. this._scrollToBottom(toBottomWithAnimate);
  346. } else {
  347. this._scrollToTop(toBottomWithAnimate);
  348. }
  349. //#endif
  350. }, c.delayTime)
  351. }
  352. },
  353. //设置本地分页数据,请求结束(成功或者失败)调用此方法,将请求的结果传递给z-paging作分页处理(若调用了此方法,则上拉加载更多时内部会自动分页,不会触发@query所绑定的事件)
  354. setLocalPaging(data, success = true) {
  355. this.isLocalPaging = true;
  356. this.$nextTick(() => {
  357. this._addData(data, success, true);
  358. })
  359. },
  360. //重新加载分页数据,pageNo会恢复为默认值,相当于下拉刷新的效果(animate为true时会展示下拉刷新动画,默认为false)
  361. reload(animate = this.showRefresherWhenReload) {
  362. if (animate) {
  363. this.privateShowRefresherWhenReload = animate;
  364. this.isUserPullDown = true;
  365. }
  366. this.listRendering = true;
  367. this.$nextTick(() => {
  368. this._preReload(animate, false);
  369. })
  370. },
  371. //刷新列表数据,pageNo和pageSize不会重置,列表数据会重新从服务端获取。必须保证@query绑定的方法中的pageNo和pageSize和传给服务端的一致
  372. refresh() {
  373. if(!this.realTotalData.length){
  374. this.reload();
  375. return;
  376. }
  377. const disPageNo = this.pageNo - this.defaultPageNo + 1;
  378. if (disPageNo >= 1) {
  379. this.loading = true;
  380. this.privateConcat = false;
  381. const totalPageSize = disPageNo * this.pageSize;
  382. this.currentRefreshPageSize = totalPageSize;
  383. this._emitQuery(this.defaultPageNo, totalPageSize, Enum.QueryFrom.Refresh);
  384. this._callMyParentQuery(this.defaultPageNo, totalPageSize);
  385. }
  386. },
  387. //手动更新列表缓存数据,将自动截取v-model绑定的list中的前pageSize条覆盖缓存,请确保在list数据更新到预期结果后再调用此方法
  388. updateCache() {
  389. if (this.finalUseCache && this.totalData.length) {
  390. this._saveLocalCache(this.totalData.slice(0, Math.min(this.totalData.length, this.pageSize)));
  391. }
  392. },
  393. //清空分页数据
  394. clean() {
  395. this._reload(true);
  396. this._addData([], true, false);
  397. },
  398. //清空分页数据
  399. clear() {
  400. this.clean();
  401. },
  402. //手动触发滚动到顶部加载更多,聊天记录模式时有效
  403. doChatRecordLoadMore() {
  404. this.useChatRecordMode && this._onLoadingMore('click');
  405. },
  406. //reload之前的一些处理
  407. _preReload(animate = this.showRefresherWhenReload, isFromMounted = true) {
  408. this.isUserReload = true;
  409. this.loadingType = Enum.LoadingType.Refresher;
  410. if (animate) {
  411. this.privateShowRefresherWhenReload = animate;
  412. // #ifndef APP-NVUE
  413. if (this.useCustomRefresher) {
  414. this._doRefresherRefreshAnimate();
  415. } else {
  416. this.refresherTriggered = true;
  417. }
  418. // #endif
  419. // #ifdef APP-NVUE
  420. this.refresherStatus = Enum.Refresher.Loading;
  421. this.refresherRevealStackCount++;
  422. setTimeout(() => {
  423. this._getNodeClientRect('zp-n-refresh-container', false).then((node) => {
  424. if (node) {
  425. let nodeHeight = node[0].height;
  426. this.nShowRefresherReveal = true;
  427. this.nShowRefresherRevealHeight = nodeHeight;
  428. setTimeout(() => {
  429. this._nDoRefresherEndAnimation(0, -nodeHeight, false, false);
  430. setTimeout(() => {
  431. this._nDoRefresherEndAnimation(nodeHeight, 0);
  432. }, 10)
  433. }, 10)
  434. }
  435. this._reload(false, isFromMounted);
  436. this._doRefresherLoad(false);
  437. });
  438. }, this.pagingLoaded ? 10 : 100)
  439. return;
  440. // #endif
  441. } else {
  442. this._refresherEnd(false, false, false, false);
  443. }
  444. this._reload(false, isFromMounted);
  445. },
  446. //重新加载分页数据
  447. _reload(isClean = false, isFromMounted = false, isUserPullDown = false) {
  448. this.isAddedData = false;
  449. this.insideOfPaging = -1;
  450. this.cacheScrollNodeHeight = -1;
  451. this.pageNo = this.defaultPageNo;
  452. this._cleanRefresherEndTimeout();
  453. !this.privateShowRefresherWhenReload && !isClean && this._startLoading(true);
  454. this.firstPageLoaded = true;
  455. this.isTotalChangeFromAddData = false;
  456. if (!this.isSettingCacheList) {
  457. this.totalData = [];
  458. }
  459. if (!isClean) {
  460. this._emitQuery(this.pageNo, this.defaultPageSize, isUserPullDown ? Enum.QueryFrom.UserPullDown : Enum.QueryFrom.Reload);
  461. let delay = 0;
  462. // #ifdef MP-TOUTIAO
  463. delay = 5;
  464. // #endif
  465. setTimeout(() => {
  466. this._callMyParentQuery();
  467. }, delay)
  468. if (!isFromMounted && this.autoScrollToTopWhenReload) {
  469. let checkedNRefresherLoading = true;
  470. // #ifdef APP-NVUE
  471. checkedNRefresherLoading = !this.nRefresherLoading;
  472. // #endif
  473. checkedNRefresherLoading && this._scrollToTop(false);
  474. }
  475. }
  476. this.$nextTick(() => {
  477. // #ifdef APP-NVUE
  478. this.nShowBottom = this.realTotalData.length > 0;
  479. // #endif
  480. })
  481. },
  482. //处理服务端返回的数组
  483. _addData(data, success, isLocal) {
  484. this.isAddedData = true;
  485. this.fromEmptyViewReload = false;
  486. this.isTotalChangeFromAddData = true;
  487. this.refresherTriggered = false;
  488. this._endSystemLoadingAndRefresh();
  489. const tempIsUserPullDown = this.isUserPullDown;
  490. if (this.showRefresherUpdateTime && this.isFirstPage) {
  491. u.setRefesrherTime(u.getTime(), this.refresherUpdateTimeKey);
  492. this.$refs.refresh && this.$refs.refresh.updateTime();
  493. }
  494. if (tempIsUserPullDown && this.isFirstPage) {
  495. this.isUserPullDown = false;
  496. }
  497. let dataTypeRes = this._checkDataType(data, success, isLocal);
  498. data = dataTypeRes.data;
  499. success = dataTypeRes.success;
  500. let delayTime = c.delayTime;
  501. // #ifdef APP-NVUE
  502. if (this.useChatRecordMode) delayTime = 0;
  503. // #endif
  504. this.loadingForNow = false;
  505. setTimeout(() => {
  506. this.pagingLoaded = true;
  507. this.$nextTick(()=>{
  508. this._refresherEnd(delayTime > 0, true, tempIsUserPullDown);
  509. })
  510. }, delayTime)
  511. if (this.isFirstPage) {
  512. this.isLoadFailed = !success;
  513. if (this.finalUseCache && success && (this.cacheMode === Enum.CacheMode.Always ? true : this.isSettingCacheList)) {
  514. this._saveLocalCache(data);
  515. }
  516. }
  517. this.isSettingCacheList = false;
  518. if (success) {
  519. if (!(this.privateConcat === false && this.loadingStatus === Enum.More.NoMore)) {
  520. this.loadingStatus = Enum.More.Default;
  521. }
  522. if (isLocal) {
  523. this.totalLocalPagingList = data;
  524. const localPageNo = this.defaultPageNo;
  525. const localPageSize = this.queryFrom !== Enum.QueryFrom.Refresh ? this.defaultPageSize : this.currentRefreshPageSize;
  526. this._localPagingQueryList(localPageNo, localPageSize, 0, (res) => {
  527. this.complete(res);
  528. })
  529. } else {
  530. let dataChangeDelayTime = 0;
  531. // #ifdef APP-NVUE
  532. if (this.privateShowRefresherWhenReload && this.finalNvueListIs === 'waterfall') {
  533. dataChangeDelayTime = 150;
  534. }
  535. // #endif
  536. setTimeout(() => {
  537. this._currentDataChange(data, this.currentData);
  538. }, dataChangeDelayTime)
  539. }
  540. } else {
  541. this._currentDataChange(data, this.currentData);
  542. this.loadingStatus = Enum.More.Fail;
  543. if (this.loadingType === Enum.LoadingType.LoadingMore) {
  544. this.pageNo --;
  545. }
  546. }
  547. },
  548. //所有数据改变时调用
  549. _totalDataChange(newVal, oldVal, eventThrow=true) {
  550. if ((!this.isUserReload || !this.autoCleanListWhenReload) && this.firstPageLoaded && !newVal.length && oldVal.length) {
  551. return;
  552. }
  553. this._doCheckScrollViewShouldFullHeight(newVal);
  554. if(!this.realTotalData.length && !newVal.length){
  555. eventThrow = false;
  556. }
  557. this.realTotalData = newVal;
  558. if (eventThrow) {
  559. this.$emit('input', newVal);
  560. // #ifdef VUE3
  561. this.$emit('update:modelValue', newVal);
  562. // #endif
  563. this.$emit('update:list', newVal);
  564. this.$emit('listChange', newVal);
  565. this._callMyParentList(newVal);
  566. }
  567. this.firstPageLoaded = false;
  568. this.isTotalChangeFromAddData = false;
  569. this.$nextTick(() => {
  570. setTimeout(()=>{
  571. this._getNodeClientRect('.zp-paging-container-content').then((res) => {
  572. if (res) {
  573. this.$emit('contentHeightChanged', res[0].height);
  574. }
  575. });
  576. },this.isIos ? 100 : 300)
  577. // #ifdef APP-NVUE
  578. if (this.useChatRecordMode && this.nIsFirstPageAndNoMore && this.isFirstPage && !this.nFirstPageAndNoMoreChecked) {
  579. this.nFirstPageAndNoMoreChecked = true;
  580. this._scrollToBottom(false);
  581. }
  582. // #endif
  583. })
  584. },
  585. //当前数据改变时调用
  586. _currentDataChange(newVal, oldVal) {
  587. newVal = [...newVal];
  588. this.listRendering = true;
  589. this.listRenderingTimeout && clearTimeout(this.listRenderingTimeout);
  590. this.$nextTick(() => {
  591. this.listRenderingTimeout = setTimeout(() => {
  592. this.listRendering = false;
  593. },100)
  594. })
  595. // #ifndef APP-NVUE
  596. this.finalUseVirtualList && this._setCellIndex(newVal,this.totalData.length === 0)
  597. this.useChatRecordMode && newVal.reverse();
  598. // #endif
  599. if (this.isFirstPage && this.finalConcat) {
  600. this.totalData = [];
  601. }
  602. if (this.customNoMore !== -1 && (this.customNoMore === 0 || !newVal.length)) {
  603. if (this.customNoMore === 0 || !newVal.length) {
  604. this.loadingStatus = Enum.More.NoMore;
  605. }
  606. } else {
  607. if (!newVal.length || (newVal.length && newVal.length < this.defaultPageSize)) {
  608. this.loadingStatus = Enum.More.NoMore;
  609. }
  610. }
  611. if (!this.totalData.length) {
  612. if (this.finalConcat) {
  613. // #ifdef APP-NVUE
  614. if(this.useChatRecordMode && this.isFirstPage && this.loadingStatus === Enum.More.NoMore){
  615. newVal.reverse();
  616. }
  617. // #endif
  618. this.totalData = newVal;
  619. }
  620. if (this.useChatRecordMode) {
  621. // #ifndef APP-NVUE
  622. this.$nextTick(() => {
  623. this._scrollToBottom(false);
  624. })
  625. // #endif
  626. }
  627. } else {
  628. if (this.useChatRecordMode) {
  629. // #ifdef APP-NVUE
  630. this.totalData = [...this.totalData, ...newVal];
  631. // #endif
  632. //#ifndef APP-NVUE
  633. const idIndex = newVal.length;
  634. let idIndexStr = `z-paging-${idIndex}`;
  635. this.totalData = [...newVal, ...this.totalData];
  636. if (this.pageNo !== this.defaultPageNo) {
  637. this.privateScrollWithAnimation = 0;
  638. this.$emit('update:chatIndex', idIndex);
  639. setTimeout(() => {
  640. this._scrollIntoView(idIndexStr, 30 + Math.max(0, this.cacheTopHeight), false, () => {
  641. this.$emit('update:chatIndex', 0);
  642. });
  643. }, this.usePageScroll ? this.isIos ? 50 : 100 : 200)
  644. } else {
  645. this.$nextTick(() => {
  646. this._scrollToBottom(false);
  647. })
  648. }
  649. //#endif
  650. } else {
  651. if (this.finalConcat) {
  652. const currentScrollTop = this.oldScrollTop;
  653. this.totalData = [...this.totalData, ...newVal];
  654. // #ifdef MP-WEIXIN
  655. if (!this.isIos && !this.refresherOnly && !this.usePageScroll && newVal.length) {
  656. this.loadingMoreTimeStamp = u.getTime();
  657. this.$nextTick(()=>{
  658. this.scrollToY(currentScrollTop);
  659. })
  660. }
  661. // #endif
  662. } else {
  663. this.totalData = newVal;
  664. }
  665. }
  666. }
  667. this.privateConcat = true;
  668. },
  669. //本地分页请求
  670. _localPagingQueryList(pageNo, pageSize, localPagingLoadingTime, callback) {
  671. pageNo = Math.max(1, pageNo);
  672. pageSize = Math.max(1, pageSize);
  673. const totalPagingList = [...this.totalLocalPagingList];
  674. const pageNoIndex = (pageNo - 1) * pageSize;
  675. const finalPageNoIndex = Math.min(totalPagingList.length, pageNoIndex + pageSize);
  676. const resultPagingList = totalPagingList.splice(pageNoIndex, finalPageNoIndex - pageNoIndex);
  677. setTimeout(() => callback(resultPagingList), localPagingLoadingTime)
  678. },
  679. //存储列表缓存数据
  680. _saveLocalCache(data) {
  681. uni.setStorageSync(this.finalCacheKey, data);
  682. },
  683. //通过缓存数据填充列表数据
  684. _setListByLocalCache() {
  685. this.totalData = uni.getStorageSync(this.finalCacheKey) || [];
  686. this.isSettingCacheList = true;
  687. },
  688. //修改父view的list
  689. _callMyParentList(newVal) {
  690. if (this.autowireListName.length) {
  691. const myParent = u.getParent(this.$parent);
  692. if (myParent && myParent[this.autowireListName]) {
  693. myParent[this.autowireListName] = newVal;
  694. }
  695. }
  696. },
  697. //调用父view的query
  698. _callMyParentQuery(customPageNo = 0, customPageSize = 0) {
  699. if (this.autowireQueryName) {
  700. if (this.myParentQuery === -1) {
  701. const myParent = u.getParent(this.$parent);
  702. if (myParent && myParent[this.autowireQueryName]) {
  703. this.myParentQuery = myParent[this.autowireQueryName];
  704. }
  705. }
  706. if (this.myParentQuery !== -1) {
  707. if (customPageSize > 0) {
  708. this.myParentQuery(customPageNo, customPageSize);
  709. } else {
  710. this.myParentQuery(this.pageNo, this.defaultPageSize);
  711. }
  712. }
  713. }
  714. },
  715. //emit query事件
  716. _emitQuery(pageNo, pageSize, from){
  717. this.queryFrom = from;
  718. this.requestTimeStamp = u.getTime();
  719. this.$emit('query', ...interceptor._handleQuery(pageNo, pageSize, from));
  720. },
  721. //检查complete data的类型
  722. _checkDataType(data, success, isLocal) {
  723. const dataType = Object.prototype.toString.call(data);
  724. if (dataType === '[object Boolean]') {
  725. success = data;
  726. data = [];
  727. } else if (dataType === '[object Null]') {
  728. data = [];
  729. } else if (dataType !== '[object Array]') {
  730. data = [];
  731. if (dataType !== '[object Undefined]') {
  732. u.consoleErr(`${isLocal ? 'setLocalPaging' : 'complete'}参数类型不正确,第一个参数类型必须为Array!`);
  733. }
  734. }
  735. return {data,success};
  736. },
  737. }
  738. }