SimplePagerDataLoader.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import { watch, ref, computed, type Ref, onMounted } from "vue"
  2. import type { ILoaderCommon, LoaderLoadType } from "./LoaderCommon";
  3. export interface ISimplePageListLoader<T, P> extends ILoaderCommon<P> {
  4. list: Ref<T[]>;
  5. page: Ref<number>;
  6. pageSize: Ref<number>;
  7. next: () => Promise<void>;
  8. prev: () => Promise<void>;
  9. total: Ref<number>;
  10. totalPages: Ref<number>;
  11. }
  12. /**
  13. * 简单分页数据封装。
  14. *
  15. * 该封装了分页数据的加载、分页、上一页、下一页等功能。当页码发生变化时,会自动调用加载函数。
  16. * 简单分页同时只能显示一页数据,重新加载会覆盖之前的数据。
  17. *
  18. * 使用示例:
  19. * ```ts
  20. * const { data, page, total, loading } = useSimplePagerDataLoader(10, async (page, pageSize) => {
  21. * const res = await fetch(`/api/data?page=${page}&pageSize=${pageSize}`);
  22. * const data = await res.json();
  23. * return {
  24. * data,
  25. * page: res.page,
  26. * total: res.total,
  27. * };
  28. * });
  29. * ```
  30. *
  31. * @param pageSize 一页的数量
  32. * @param loader 加载函数
  33. * @returns
  34. */
  35. export function useSimplePagerDataLoader<T, P = any>(
  36. _pageSize: number|Ref<number>,
  37. loader: (page: number, pageSize: number, params?: P) => Promise<{
  38. list: T[],
  39. total: number,
  40. }>,
  41. options?: {
  42. /**
  43. * 是否追加数据,而不是覆盖数据。
  44. * @default false
  45. */
  46. append: boolean,
  47. /**
  48. * 是否在初始化时加载数据。
  49. * @default true
  50. */
  51. loadOnInit: boolean,
  52. },
  53. ) : ISimplePageListLoader<T, P>
  54. {
  55. const {
  56. append = false,
  57. loadOnInit = true,
  58. } = options || {};
  59. const page = ref(0);
  60. const pageSize = computed(() => {
  61. return typeof _pageSize == 'object'? _pageSize.value : _pageSize;
  62. });
  63. const list = ref<T[]>([]) as Ref<T[]>;
  64. const total = ref(0);
  65. const totalPages = computed(() => Math.ceil(total.value / pageSize.value));
  66. const loadStatus = ref<LoaderLoadType>('loading');
  67. const loadError = ref('');
  68. watch(page, async () => {
  69. await loadData(lastParams, false);
  70. });
  71. let lastParams: P | undefined;
  72. let loading = false;
  73. async function loadData(params?: P, refresh: boolean = false) {
  74. if (loading)
  75. return;
  76. if (params)
  77. lastParams = params;
  78. if (refresh) {
  79. page.value = 1;
  80. list.value = [];
  81. }
  82. loadStatus.value = 'loading';
  83. loading = true;
  84. try {
  85. const res = (await loader(page.value, pageSize.value, lastParams));
  86. list.value = append ? list.value.concat(res.list) : res.list;
  87. total.value = res.total;
  88. loadStatus.value = res.list.length > 0 ? 'finished' : 'nomore';
  89. loadError.value = '';
  90. loading = false;
  91. } catch(e) {
  92. loadError.value = '' + e;
  93. loadStatus.value = 'error';
  94. loading = false;
  95. }
  96. }
  97. /**
  98. * 下一页
  99. */
  100. async function next() {
  101. if (page.value > totalPages.value)
  102. return;
  103. page.value++;
  104. await loadData(lastParams, false);
  105. }
  106. /**
  107. * 上一页
  108. */
  109. async function prev() {
  110. if (page.value <= 1)
  111. return;
  112. page.value--;
  113. await loadData(lastParams, false);
  114. }
  115. onMounted(() => {
  116. if (loadOnInit) {
  117. loadData(lastParams, true);
  118. }
  119. });
  120. return {
  121. loadData,
  122. next,
  123. prev,
  124. /**
  125. * 数据
  126. */
  127. list,
  128. /**
  129. * 当前页码
  130. */
  131. page,
  132. pageSize,
  133. /**
  134. * 总数据条数
  135. */
  136. total,
  137. /**
  138. * 总页数
  139. */
  140. totalPages,
  141. loadError,
  142. loadStatus,
  143. }
  144. }