在vue中简化element-plus的表格&分页

14 阅读1分钟
import { reactive, ref, watch } from 'vue'

export type Pagination = {
  currentPage: number
  pageSize: number
  total: number
}

/**
 * 简化表格和分页
 * @example
 * ```js
 * const { data, loading, pagination, error } = usePagniation(getData)
 * ```
 * ```html
 * <ElPagination v-bind="page" />
 * ```
 */
export function usePagniation<T extends { total: number; list: any[] }>(
  getData: (pagination: Pick<Pagination, 'currentPage' | 'pageSize'>) => Promise<T> | T,
  config?: { defaultPage?: number; defaultPageSize?: number },
) {
  const { defaultPage = 1, defaultPageSize = 10 } = config ?? {}
  const data = ref([] as T['list'])
  const loading = ref(true)
  const error = ref<null | unknown>(null)
  const pagination = reactive<
    Pagination & {
      'onUpdate:currentPage': (val: number) => void
      'onUpdate:pageSize': (val: number) => void
    }
  >({
    currentPage: defaultPage,
    pageSize: defaultPageSize,
    total: 0,
    'onUpdate:currentPage': (val) => {
      pagination.currentPage = val
    },
    'onUpdate:pageSize': (val) => {
      pagination.pageSize = val
    },
  })
  let key = 0
  async function _loadData(currentPage: number, pageSize: number) {
    ++key
    const currentKey = key
    loading.value = true
    error.value = null
    try {
      const res = await getData({
        currentPage,
        pageSize,
      })
      if (key !== currentKey) return
      const { list, total } = res
      data.value = list
      pagination.total = total
    } catch (e) {
      if (key === currentKey) {
        error.value = e
      }
    } finally {
      if (key === currentKey) {
        loading.value = false
      }
    }
  }

  watch(
    () => [pagination.currentPage, pagination.pageSize],
    ([currentPage, pageSize]) => _loadData(currentPage, pageSize),
    { immediate: true },
  )
  return {
    data,
    loading,
    error,
    pagination: pagination as Pagination,
    /** 手动获取数据 可以修改分页 */
    loadData(newPagination: Partial<Pick<Pagination, 'currentPage' | 'pageSize'>> = {}) {
      const { currentPage = pagination.currentPage, pageSize = pagination.pageSize } = newPagination
      if (currentPage === pagination.currentPage && pageSize === pagination.pageSize) {
        // 分页未变化 直接获取数据
        _loadData(pagination.currentPage, pagination.pageSize)
        return
      }
      // 分页变化 设置pagination 由watch获取数据
      pagination.currentPage = currentPage
      pagination.pageSize = pageSize
    },
  }
}

特点:1.使用key避免网络请求后发先至从 2.利用v-bind简化数据和值的绑定