SimplePagerDataLoader.ts 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import { watch, ref, computed, type Ref } 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. }>) : ISimplePageListLoader<T, P>
  41. {
  42. const page = ref(0);
  43. const pageSize = computed(() => {
  44. return typeof _pageSize == 'object'? _pageSize.value : _pageSize;
  45. });
  46. const list = ref<T[]>([]) as Ref<T[]>;
  47. const total = ref(0);
  48. const totalPages = computed(() => Math.ceil(total.value / pageSize.value));
  49. const loadStatus = ref<LoaderLoadType>('loading');
  50. const loadError = ref('');
  51. watch(page, async () => {
  52. await loadData(lastParams, false);
  53. });
  54. let lastParams: P | undefined;
  55. let loading = false;
  56. async function loadData(params?: P, refresh: boolean = false) {
  57. if (loading)
  58. return;
  59. if (params)
  60. lastParams = params;
  61. if (refresh) {
  62. page.value = 1;
  63. list.value = [];
  64. }
  65. loadStatus.value = 'loading';
  66. loading = true;
  67. try {
  68. const res = (await loader(page.value, pageSize.value, lastParams));
  69. list.value = list.value.concat(res.list);
  70. total.value = res.total;
  71. loadStatus.value = res.list.length > 0 ? 'finished' : 'nomore';
  72. loadError.value = '';
  73. loading = false;
  74. } catch(e) {
  75. loadError.value = '' + e;
  76. loadStatus.value = 'error';
  77. loading = false;
  78. }
  79. }
  80. /**
  81. * 下一页
  82. */
  83. async function next() {
  84. if (page.value > totalPages.value)
  85. return;
  86. page.value++;
  87. await loadData(lastParams, false);
  88. }
  89. /**
  90. * 上一页
  91. */
  92. async function prev() {
  93. if (page.value <= 1)
  94. return;
  95. page.value--;
  96. await loadData(lastParams, false);
  97. }
  98. return {
  99. loadData,
  100. next,
  101. prev,
  102. /**
  103. * 数据
  104. */
  105. list,
  106. /**
  107. * 当前页码
  108. */
  109. page,
  110. pageSize,
  111. /**
  112. * 总数据条数
  113. */
  114. total,
  115. /**
  116. * 总页数
  117. */
  118. totalPages,
  119. loadError,
  120. loadStatus,
  121. }
  122. }