index.vue 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. <template>
  2. <view class="lsv-container">
  3. <mescroll-uni
  4. ref="mescrollRef"
  5. :fixed="false"
  6. :up="upOption"
  7. :down="downOption"
  8. @up="upCallback"
  9. @down="downCallback"
  10. @init="mescrollInit"
  11. @scroll="onScroll"
  12. @emptyclick="onEmptyClick">
  13. <view class="lsv-list">
  14. <slot name="list" :data="dataList" :is-scrolling="isScrolling"></slot>
  15. </view>
  16. </mescroll-uni>
  17. </view>
  18. </template>
  19. <script>
  20. export default {
  21. name: '',
  22. props: {
  23. // 数据接口
  24. api: {
  25. type: Object,
  26. required: true,
  27. default: null
  28. },
  29. // 初始参数
  30. init: {
  31. type: Object,
  32. default: () => ({})
  33. },
  34. emptyText: {
  35. type: String,
  36. default: ''
  37. },
  38. emptyBtnText: {
  39. type: String,
  40. default: ''
  41. },
  42. // 自定义list数据的字段
  43. keyName: {
  44. type: String,
  45. default: 'records'
  46. },
  47. // page相关
  48. noPage: {
  49. type: Boolean,
  50. default: false
  51. },
  52. pageSize: {
  53. type: [Number, String],
  54. default: 10
  55. },
  56. downEnabled: {
  57. type: Boolean,
  58. default: true
  59. },
  60. upTextVisible: {
  61. type: Boolean,
  62. default: true
  63. },
  64. },
  65. data() {
  66. return {
  67. params: {},
  68. dataList: [],
  69. // 是否滚动
  70. isScrolling: false,
  71. scrollTimer: null
  72. };
  73. },
  74. computed: {
  75. downOption() {
  76. return {
  77. use: this.downEnabled
  78. };
  79. },
  80. // 上拉加载的配置
  81. upOption() {
  82. let obj = {
  83. // noMoreSize: 5, // 如果列表已无数据,可设置列表的总数量要大于5条才显示无更多数据;
  84. onScroll: true,
  85. showLoadMoreText: this.upTextVisible,
  86. textLoading: this.upTextVisible ? '加载中 ...' : '',
  87. textNoMore: this.upTextVisible ? '-- 暂无更多数据 --' : '',
  88. page: {
  89. size: this.pageSize // 每页数据的数量,默认10
  90. },
  91. empty: {
  92. use: true,
  93. tip: this.emptyText || '暂无数据',
  94. btnText: this.emptyBtnText,
  95. // icon: '/static/common/empty.png',
  96. }
  97. };
  98. return obj;
  99. }
  100. },
  101. methods: {
  102. // scroll
  103. mescrollInit(e) {
  104. this.mescroll = e;
  105. },
  106. onScroll(e) {
  107. this.isScrolling = true;
  108. // 使用防抖判断滚动结束
  109. clearTimeout(this.scrollTimer);
  110. this.scrollTimer = setTimeout(() => {
  111. this.isScrolling = false;
  112. }, 200);
  113. },
  114. // 下拉刷新
  115. downCallback() {
  116. this.mescroll.resetUpScroll();
  117. },
  118. // 上拉加载
  119. upCallback(e) {
  120. if (!this.api) {
  121. this.mescroll.endErr();
  122. return;
  123. }
  124. let options = {}, params = {
  125. pageNo: e.num,
  126. pageSize: e.size,
  127. ...this.init,
  128. ...this.params
  129. };
  130. // request底层问题
  131. if (this.api.method === 'POST') {
  132. options.data = params;
  133. } else if (this.api.method === 'GET') {
  134. options.params = params;
  135. }
  136. // 置空
  137. if(e.num == 1) this.dataList = [];
  138. // 请求
  139. this.$http.request({
  140. ...this.api,
  141. ...options
  142. }).then(res => {
  143. if (res.data.code === 200) {
  144. let r = res.data.result;
  145. // 无分页处理,用于那些需要下拉和空列表的地方
  146. if (this.noPage) {
  147. r = {
  148. records: Array.isArray(r) ? r : [],
  149. total: Array.isArray(r) ? r.length : 0
  150. };
  151. }
  152. let result = r || {};
  153. let records = [];
  154. let total = 0;
  155. // 标准分页:{ records, total }
  156. if (Array.isArray(result[this.keyName])) {
  157. records = result[this.keyName];
  158. total = result.total;
  159. }
  160. // 嵌套分页:{ page: { records, total }, summary? }
  161. else if (result.page && Array.isArray(result.page.records)) {
  162. records = result.page.records;
  163. total = result.page.total;
  164. }
  165. this.$emit('afterFetch', result);
  166. // 数据
  167. this.dataList = this.dataList.concat(records);
  168. this.mescroll.endBySize(records.length, total || 0);
  169. } else {
  170. this.$tip.error(res.data.message || '数据请求发生错误');
  171. this.mescroll.endErr();
  172. }
  173. }).catch(e => {
  174. this.mescroll.endErr();
  175. });
  176. },
  177. reloadList(p) {
  178. this.params = p || this.params;
  179. if (this.mescroll) this.mescroll.resetUpScroll();
  180. },
  181. onEmptyClick() {
  182. this.$emit('emptyclick');
  183. }
  184. }
  185. }
  186. </script>
  187. <style lang="scss" scoped>
  188. .lsv-container {
  189. height: 100%;
  190. position: relative;
  191. .lsv-list {
  192. min-height: 100%;
  193. }
  194. }
  195. </style>