Skip to content

ProTable 数据表格 1.1.0

基于 el-table 进行封装的 JSON 配置化表格,属性、方法完全兼容,用于快速构建表格

基础用法

内置分页组件,使用 hide-pagination 属性控制是否显示分页

显示分页
共 100 条
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 10
前往

<template>
  <div>
    <el-switch
      v-model="hidePagination"
      active-text="隐藏分页"
      inactive-text="显示分页"
      style="margin-bottom: 10px"
    />

    <pro-table
      ref="proTableRef"
      border
      stripe
      height="400px"
      :data="data"
      :columns="columns"
      :total="total"
      :hide-pagination="hidePagination"
      @pagination-change="handlePagination"
    />
  </div>
</template>

<script setup lang="tsx">
import { computed, ref } from 'vue'
import { ProTable } from '@coderhd/pro-element-plus'
import type { ProTableColumn } from '@coderhd/pro-element-plus'

const proTableRef = ref<InstanceType<typeof ProTable>>()
const data = ref<any>(
  Array.from({ length: 20 }).map((_, index) => ({
    index: index + 1,
    name: '姓名',
    age: Math.floor(Math.random() * 100),
    sex: Math.random() > 0.5 ? '男' : '女',
    address: '北京市海淀区',
    desc: '很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长的描述',
  })),
)
const hidePagination = ref<boolean>(false)
const total = ref<number>(100)

const columns = computed<ProTableColumn[]>(() => [
  {
    label: '姓名',
    prop: 'name',
    width: 100,
  },
  {
    label: '年龄',
    prop: 'age',
    width: 100,
  },
  {
    label: '性别',
    prop: 'sex',
    width: 100,
  },
  {
    label: '地址',
    prop: 'address',
  },
  {
    label: '描述',
    prop: 'desc',
    showOverflowTooltip: true,
  },
  {
    label: '操作',
    prop: 'action',
    width: 140,
    cellSlots: {
      default: (scope) => {
        return (
          <div>
            <el-button
              type="primary"
              size="small"
              // eslint-disable-next-line no-console
              onClick={() => console.log(scope)}
            >
              编辑
            </el-button>

            <el-button type="danger" size="small">
              删除
            </el-button>
          </div>
        )
      },
      header: () => '自定义',
    },
  },
])

const handlePagination = (page: number, pageSize: number) => {
  // eslint-disable-next-line no-console
  console.log({ page, pageSize })
  proTableRef.value?.scrollTo({ top: 0, behavior: 'smooth' })
}
</script>

<style scoped></style>

查询表格

配合 pro-search-form 组件使用,实现查询表格功能

姓名:
年龄:
性别:
请选择性别
日期:
状态:
暂无数据
共 100 条
  • 1
  • 2
  • 3
  • 4
  • 5
前往

<template>
  <div v-loading="loading">
    <pro-search-form
      label-width="80px"
      label-suffix=":"
      :model="searchForm"
      :gutter="20"
      :fields="fields"
      :auto-search-debounce="300"
      @search="handleSearch"
    />

    <pro-table
      ref="proTableRef"
      v-model:current-page="currentPage"
      v-model:page-size="pageSize"
      border
      stripe
      height="400px"
      :data="data"
      :columns="columns"
      :total="total"
      background
      @pagination-change="handlePagination"
    />
  </div>
</template>

<script setup lang="tsx">
import { computed, reactive, ref } from 'vue'
import { ProTable } from '@coderhd/pro-element-plus'
import type { ProFormFields, ProTableColumn } from '@coderhd/pro-element-plus'

const proTableRef = ref<InstanceType<typeof ProTable>>()

const searchForm = reactive({})
const currentPage = ref<number>(1)
const pageSize = ref<number>(20)
const data = ref<any>([])
const total = ref<number>(100)
const loading = ref<boolean>(false)

const fields = computed<ProFormFields>(() => [
  {
    label: '姓名',
    prop: 'name',
    component: 'ElInput',
    componentProps: {
      placeholder: '请输入姓名',
    },
    colProps: {
      span: 8,
    },
  },
  {
    label: '年龄',
    prop: 'age',
    component: 'ElInputNumber',
    componentProps: {
      placeholder: '请输入年龄',
      style: { width: '100%' },
    },
    colProps: {
      span: 8,
    },
  },
  {
    label: '性别',
    prop: 'sex',
    component: 'ElSelect',
    componentProps: {
      placeholder: '请选择性别',
      options: [
        { label: '男', value: '1' },
        { label: '女', value: '2' },
      ],
    },
    colProps: {
      span: 8,
    },
  },
  {
    label: '日期',
    prop: 'date',
    component: 'ElDatePicker',
    componentProps: {
      placeholder: '请选择日期',
    },
    colProps: {
      span: 8,
    },
  },
  {
    label: '状态',
    prop: 'status',
    component: 'ElSwitch',
    componentProps: {
      activeValue: true,
      inactiveValue: false,
    },
    colProps: {
      span: 8,
    },
  },
])

const columns = computed<ProTableColumn[]>(() => [
  {
    label: '序号',
    prop: 'index',
    width: 100,
  },
  {
    label: '姓名',
    prop: 'name',
    width: 100,
  },
  {
    label: '年龄',
    prop: 'age',
    width: 100,
  },
  {
    label: '性别',
    prop: 'sex',
    width: 100,
  },
  {
    label: '地址',
    prop: 'address',
  },
  {
    label: '描述',
    prop: 'desc',
    showOverflowTooltip: true,
  },
  {
    label: '操作',
    prop: 'action',
    width: 140,
    cellSlots: {
      default: (scope) => {
        return (
          <div>
            <el-button
              type="primary"
              size="small"
              // eslint-disable-next-line no-console
              onClick={() => console.log(scope)}
            >
              编辑
            </el-button>

            <el-button type="danger" size="small">
              删除
            </el-button>
          </div>
        )
      },
      header: () => '自定义',
    },
  },
])

const handleSearch = () => {
  currentPage.value = 1
  request()
}

const request = async () => {
  loading.value = true
  data.value = await new Promise((resolve) => {
    setTimeout(() => {
      resolve(
        Array.from({ length: pageSize.value }).map((_, index) => ({
          index: (currentPage.value - 1) * pageSize.value + index + 1,
          name: '姓名',
          age: Math.floor(Math.random() * 100),
          sex: Math.random() > 0.5 ? '男' : '女',
          address: '北京市海淀区',
          desc: '很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长的描述',
        })),
      )
    }, 1000)
  })
  loading.value = false
}

const handlePagination = (page: number, pageSize: number) => {
  // eslint-disable-next-line no-console
  console.log({ page, pageSize })

  request()
  proTableRef.value?.scrollTo({ top: 0, behavior: 'smooth' })
}
</script>

<style scoped></style>

Attributes

更多属性参考 ElementPlus Table Attributes

属性名类型默认值说明
columnsProTableColumn[][]列配置
hide-paginationbooleanfalse是否隐藏分页

Events

更多事件参考 ElementPlus Table Events

事件名说明回调参数
pagination-change当分页发生变化时,触发的事件(currentPage: number, pageSize: number): void

Slots

插槽名说明
append插入至表格最后一行之后的内容, 如果需要对表格的内容进行无限滚动操作,可能需要用到这个 slot。 若表格有合计行,该 slot 会位于合计行之上。
empty空数据时显示的内容

Exposes

更多实例方法参考ElementPlus Table Methods

类型定义
ts
// import tableProps from 'element-plus/es/components/table/src/table/defaults'
import tableColumnProps from 'element-plus/es/components/table/src/table-column/defaults'

import type { ExtractPublicPropTypes, PropType, VNodeChild } from 'vue'
import type { TableProps, TableColumnCtx, PaginationProps } from 'element-plus'

type DefaultRow = Record<PropertyKey, any>

type CellSlots = {
  default?: (data: {
    row: any
    column: TableColumnCtx<any>
    $index: number
  }) => VNodeChild
  header?: (data: { column: TableColumnCtx<any>; $index: number }) => VNodeChild
  filterIcon?: (data: { filterOpened: boolean }) => VNodeChild
  expand?: (data: { expanded: boolean }) => VNodeChild
}

export const proTableColumn = {
  ...tableColumnProps,
  /**
   * 列插槽
   */
  cellSlots: {
    type: Object as PropType<CellSlots>,
    default: () => ({}),
  },
}

export type ProTableColumn = ExtractPublicPropTypes<typeof proTableColumn>

export type ProTableProps<T extends DefaultRow = DefaultRow> = TableProps<T> &
  Partial<PaginationProps> & {
    /**
     * 列配置
     */
    columns: ProTableColumn[]
    /**
     * 是否隐藏分页
     * @default false
     */
    hidePagination?: boolean
  }