Skip to content

ProTable

示例

基本使用

props为$index自动生成索引

<template>
  <div>
    <SuperProTable
      ref="proTable"
      :columns="columns"
      :data="data"
    ></SuperProTable>
  </div>
</template>

<script lang="ts" setup>
import { reactive } from 'vue'
import type { ColumnProps } from '@super-ui-plus/types'

const data = reactive<any[]>([
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
])

const columns = reactive<ColumnProps<any>[]>([
  { prop: '$index', label: '序号', width: 80 },
  { prop: 'date', label: '日期', width: 200 },
  { prop: 'name', label: '姓名', width: 200 },
  { prop: 'address', label: '居住地址' },
])
</script>

单元格数据状态(tag)

传入tag函数实现不同数据状态样式

<template>
  <div>
    <SuperProTable
      ref="proTable"
      :columns="columns"
      :data="data"
    ></SuperProTable>
  </div>
</template>

<script lang="ts" setup>
import { reactive } from 'vue'
import type { ColumnProps } from '@super-ui-plus/types'

const data = reactive<any[]>([
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
    tag: 0
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
    tag: 1
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
    tag: 2
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
    tag: 3
  },
])

const columns = reactive<ColumnProps<any>[]>([
  { prop: 'date', label: '日期', width: 200 },
  { prop: 'name', label: '姓名', width: 200 },
  { prop: 'address', label: '居住地址' },
  {
    prop: 'tag',
    label: '标签',
    tag: ({ row }) => {
      switch (row.tag) {
        case 0:
          return { type: 'success' }
        case 1:
          return { type: 'info' }
        case 2:
          return { type: 'warning' }
        case 3:
          return { type: 'danger' }
        default:
          break
      }
    },
  },
])
</script>

单元格对齐方式

表格默认为居中对齐,如果需要修改对齐方式,请设置align属性, 每列对齐方式可以单独设置

<template>
  <div>
    <SuperProTable
      ref="proTable"
      :columns="columns"
      :data="data"
      align="left"
    ></SuperProTable>
  </div>
</template>

<script lang="ts" setup>
import { reactive } from 'vue'
import type { ColumnProps } from '@super-ui-plus/types'

const data = reactive<any[]>([
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
])

const columns = reactive<ColumnProps<any>[]>([
  { prop: 'date', label: '日期', width: 200 },
  { prop: 'name', label: '姓名', width: 200, align: 'center' },
  { prop: 'address', label: '居住地址' },
])
</script>

固定表头

设置 height 属性,即可实现固定表头的表格

<template>
  <div>
    <SuperProTable
      ref="proTable"
      :columns="columns"
      :data="data"
      height="300px"
    ></SuperProTable>
  </div>
</template>

<script lang="ts" setup>
import { reactive } from 'vue'
import type { ColumnProps } from '@super-ui-plus/types'

const data = reactive<any[]>([])

Array.from({ length: 50 }).forEach((_, index) => {
  data.push({
    date: Date.now(),
    name: '张三' + index,
    address: '北京' + index,
  },)
})

const columns = reactive<ColumnProps<any>[]>([
  { prop: 'date', label: '日期', width: 200 },
  { prop: 'name', label: '姓名', width: 200 },
  { prop: 'address', label: '居住地址' },
])
</script>

多级表头

设置 _children 属性,即可实现多级表头表格

<template>
  <div>
    <SuperProTable ref="proTable" :columns="columns" :data="data"></SuperProTable>
  </div>
</template>

<script lang="ts" setup>
import { reactive } from 'vue'
import type { ColumnProps } from '@super-ui-plus/types'

const data = reactive<any[]>([
  {
    date: Date.now(),
    name: '张三',
    province: "湖北省",
    city: "武汉市",
    area: "汉阳区",
  },
  {
    date: Date.now(),
    name: '张三',
    province: "湖北省",
    city: "武汉市",
    area: "汉阳区",
  },
  {
    date: Date.now(),
    name: '张三',
    province: "湖北省",
    city: "武汉市",
    area: "汉阳区",
  },
])

const columns = reactive<ColumnProps<any>[]>([
  { prop: 'date', label: '日期' },
  {
    prop: 'base',
    label: '配送信息',
    _children: [
      { prop: 'name', label: '姓名' },
      {
        prop: 'address',
        label: '地址',
        _children: [
          { prop: 'province', label: '省份' },
          { prop: 'city', label: '市区' },
          { prop: 'area', label: '具体地址' },
        ],
      },
    ],
  },
])
</script>

表格多选

警告: rowKey必须设置

<template>
  <div>
    <div>选中的数据: {{ selectedList }}</div>
    <div>选中的数据id: {{ selectedListIds }}</div>
    <el-checkbox v-model="ifContinuousMultiple">是否开启连续勾选列表数据({{ ifContinuousMultiple }})</el-checkbox>
    <el-button @click="() => treeProTableRef.clearSelection()">清空数据</el-button>
    <SuperProTable
      ref="proTable"
      rowKey="id"
      :columns="columns"
      :data="data"
      :ifContinuousMultiple="ifContinuousMultiple"
    ></SuperProTable>
  </div>
</template>

<script lang="ts" setup>
import { ref, reactive, useTemplateRef, computed } from 'vue'
import type { ColumnProps } from '@super-ui-plus/types'

const ifContinuousMultiple = ref(true)
const data = reactive<any[]>([])

Array.from({ length: 50 }).forEach((_, index) => {
  data.push({
    id: index,
    date: Date.now(),
    name: '张三' + index,
    address: '北京' + index,
  },)
})

const columns = reactive<ColumnProps<any>[]>([
  { type: 'selection', width: 80 },
  { prop: 'date', label: '日期', width: 200 },
  { prop: 'name', label: '姓名', width: 200 },
  { prop: 'address', label: '居住地址' },
])

const treeProTableRef: any = useTemplateRef('proTable')
const selectedList: any = computed(() => treeProTableRef.value?.selectedList)
const selectedListIds: any = computed(() => treeProTableRef.value?.selectedListIds)

</script>

多选树

<template>
  <div>
    <div>选中的数据: {{ selectedList }}</div>
    <div>选中的数据id: {{ selectedListIds }}</div>
    <el-button @click="() => treeProTableRef.clearSelection()">清空数据</el-button>
    <SuperProTable ref="treeProTable" :columns="treeColumns" :data="treeData"></SuperProTable>
  </div>
</template>

<script lang="ts" setup>
import { reactive, useTemplateRef, computed } from 'vue'
import type { ColumnProps } from '@super-ui-plus/types'

// 生成树形结构数据
// 定义树节点类型
interface TreeNode {
  id: string
  date: number
  name: string
  address: string
  children?: TreeNode[]
}
const generateTreeData = (level = 0, count = 10, parentId: string | null = null) => {
  const data: TreeNode[] = []
  for (let i = 0; i < count; i++) {
    const id = parentId ? `${parentId}-${i}` : `${i}`
    const item: TreeNode = {
      id,
      date: Date.now(),
      name: `张三${level}-${i}`,
      address: `北京${level}-${i}`,
    }

    // 添加子节点(最多3层)
    if (level < 2 && Math.random() > 0.3) {
      item.children = generateTreeData(level + 1, Math.floor(Math.random() * 3) + 1, id)
    }

    data.push(item)
  }
  return data
}
const treeData = reactive<any[]>(generateTreeData())

const treeColumns = reactive<ColumnProps<any>[]>([
  { type: 'selection', width: 80 },
  { type: 'index', width: 80 },
  { prop: 'date', label: '日期' },
  { prop: 'name', label: '姓名' },
  { prop: 'address', label: '地址' },
])
const treeProTableRef: any = useTemplateRef('treeProTable')
const selectedList: any = computed(() => treeProTableRef.value?.selectedList)
const selectedListIds: any = computed(() => treeProTableRef.value?.selectedListIds)
</script>

展开行/单选列/拖拽排序

<template>
  <div>
    <SuperProTable ref="proTable" :columns="columns" :data="data" rowKey="id" @drag-sort="sortTable">
      <template #expand="scope">
        {{ scope.row }}
      </template>
    </SuperProTable>
  </div>
</template>

<script lang="ts" setup>
import { reactive, useTemplateRef, watch } from 'vue'
import { ElMessage } from 'element-plus'
import type { ColumnProps } from '@super-ui-plus/types'

const data = reactive<any[]>([
  {
    id: 1,
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
  {
    id: 2,  
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
  {
    id: 3,
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
])

const columns = reactive<ColumnProps<any>[]>([
  { type: "sort", label: "Sort", width: 60 },
  { type: 'radio', label: '单选', width: 60 },
  { type: 'expand', label: 'Expand', width: 60 },
  { prop: 'date', label: '日期' },
  { prop: 'name', label: '姓名' },
  { prop: 'address', label: '居住地址' },
])

const proTableRef = useTemplateRef('proTable')

watch(
  () => proTableRef.value?.radio,
  () =>
    proTableRef.value?.radio &&
    ElMessage.success(`选中 id 为【${proTableRef.value?.radio}】的数据`),
)

// 表格拖拽排序
const sortTable = ({ newIndex, oldIndex }: { newIndex?: number; oldIndex?: number }) => {
  console.log(newIndex, oldIndex);
  console.log(proTableRef.value?.tableData);
  ElMessage.success("修改列表排序成功");
};
</script>

自定义渲染表头(slot/tsx)

通过 插槽 和 headerRender 属性,可以自定义表头

<template>
  <div>
    <SuperProTable ref="proTable" :columns="columns" :data="data">
      <template #usernameHeader="scope">
        <el-button type="primary" @click="ElMessage.success('我是通过作用域插槽渲染的表头')">
          {{ scope.column.label }}
        </el-button>
      </template>
    </SuperProTable>
  </div>
</template>

<script lang="tsx" setup>
import { reactive } from 'vue'
import { ElButton, ElMessage } from 'element-plus'
import type { ColumnProps } from '@super-ui-plus/types'

const data = reactive<any[]>([
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
    username: '无名的人'
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
    username: '无名的人'
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
    username: '无名的人'
  },
])

// 自定义渲染表头(使用tsx语法)
const headerRender = (scope: any) => {
  return (
    <ElButton type="primary" onClick={() => ElMessage.success('我是通过 tsx 语法渲染的表头')}>
      {scope.column.label}
    </ElButton>
  )
}

const columns = reactive<ColumnProps<any>[]>([
  { prop: 'date', label: '日期', headerRender, width: 200 },
  { prop: 'name', label: '姓名', width: 200 },
  { prop: 'address', label: '居住地址' },
  { prop: 'username', label: '用户名' },
])
</script>

自定义渲染内容(slot/tsx)

通过 插槽 和 reder 属性,可以自定义单元格内容

<template>
  <div>
    <SuperProTable ref="proTable" :columns="columns" :data="data">
      <template #name="scope">
        <el-button type="primary" link @click="ElMessage.success('我是通过作用域插槽渲染的内容')">
          {{ scope.row.name }}
        </el-button>
      </template>
    </SuperProTable>
  </div>
</template>

<script lang="tsx" setup>
import { reactive } from 'vue'
import { ElButton, ElMessage } from 'element-plus'
import type { ColumnProps } from '@super-ui-plus/types'

const data = reactive<any[]>([
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
])

const columns = reactive<ColumnProps<any>[]>([
  { prop: '$index', label: '序号', width: 80 },
  { prop: 'date', label: '日期', width: 200 },
  { prop: 'name', label: '姓名', width: 200 },
  {
    prop: 'address',
    label: '居住地址',
    render: scope => {
      return (
        <ElButton
          type="primary"
          link
          onClick={() => ElMessage.success('我是通过 tsx 语法渲染的内容')}
        >
          {scope.row.address}
        </ElButton>
      )
    },
  },
])
</script>

表尾合计行

show-summary属性显示表尾合计行
sumText: 自定义合计行文本
sumNaNText: 当数据为非数字时,该字段用于代替合计行显示的值
sumDataPrefix: 自定义合计数据前缀
sumFilter: 自定义合计内容

<template>
  <div>
    <SuperProTable
      ref="proTable"
      :columns="columns"
      :data="data"
      :show-summary="true"
      sumText="自定义合计行文本"
      sumNaNText="自定义非数字数据"
    ></SuperProTable>
  </div>
</template>

<script lang="ts" setup>
import { reactive } from 'vue'
import type { ColumnProps } from '@super-ui-plus/types'

const data = reactive<any[]>([
  {
    name: '张三',
    chineseZodiac: '🐎',
    n1: '1',
    n2: '2',
    n3: '3',
    n4: '4',
    n5: '5',
  },
  {
    name: '张三',
    chineseZodiac: '🐎',
    n1: '1',
    n2: '2',
    n3: '3',
    n4: '4',
    n5: '5',
  },
  {
    name: '张三',
    chineseZodiac: '🐎',
    n1: '1',
    n2: '2',
    n3: '3',
    n4: '4',
    n5: '5',
  },
])

const columns = reactive<ColumnProps<any>[]>([
  { prop: '$index', label: '序号', width: 80 },
  { prop: 'name', label: '姓名' },
  { prop: 'chineseZodiac', label: '生肖', sumFilter:  () => '🐎' },
  { prop: 'n1', label: '数值1', sumDataPrefix: '$' },
  { prop: 'n2', label: '数值2', sumDataPrefix: '' },
  { prop: 'n3', label: '数值3', sumFilter: (val) => '$' + val },
  { prop: 'n4', label: '数值4', sumDataPrefix: '' },
  { prop: 'n5', label: '数值5' },
])
</script>

分页自动滚动到首行

通过 autoScroll 控制分页自动滚动到首行

<template>
  <div>
    <SuperProTable
      ref="proTable"
      :columns="columns"
      :data="data"
      :autoScroll="true"
      height="300px"
    ></SuperProTable>
  </div>
</template>

<script lang="ts" setup>
import { reactive } from 'vue'
import type { ColumnProps } from '@super-ui-plus/types'

const data = reactive<any[]>([])

Array.from({ length: 50 }).forEach(() => {
  data.push({
    date: Date.now(),
    name: '王小虎',
    address: '上海市普陀区金沙江路 1518 弄'
  })
})

const columns = reactive<ColumnProps<any>[]>([
  { prop: '$index', label: '序号', width: 80 },
  { prop: 'date', label: '日期', width: 200 },
  { prop: 'name', label: '姓名', width: 200 },
  { prop: 'address', label: '居住地址' },
])
</script>

数据格式化

通过 format 实现数据格式化
目前只内置了日期格式化,通过传入 year,month,date显示效果

<template>
  <div>
    <SuperProTable
      ref="proTable"
      :columns="columns"
      :data="data"
    ></SuperProTable>
  </div>
</template>

<script lang="ts" setup>
import { reactive } from 'vue'
import type { ColumnProps } from '@super-ui-plus/types'

const data = reactive<any[]>([
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
    tag: 0,
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
    tag: 0,
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
    tag: 0,
  },
])

const columns = reactive<ColumnProps<any>[]>([
  { prop: '$index', label: '序号', width: 80 },
  { prop: 'date', label: '日期', format: 'year', width: 100 },
  { prop: 'name', label: '姓名', width: 100 },
  { prop: 'address', label: '居住地址', format: value => '我家住在:' + value },
  {
    prop: 'tag',
    label: '标签',
    tag: ({ row }) => {
      switch (row.tag) {
        case 0:
          return { type: 'success' }
        case 1:
          return { type: 'info' }
        case 2:
          return { type: 'warning' }
        case 3:
          return { type: 'danger' }
        default:
          break
      }
    },
    width: 100
  },
])
</script>

行和列合并

通过 span-method 实现

<template>
  <div>
    <SuperProTable
      ref="proTable"
      :columns="columns"
      :data="data"
      :span-method="objectSpanMethod"
    ></SuperProTable>
  </div>
</template>

<script lang="ts" setup>
import { reactive } from 'vue'
import type { ColumnProps } from '@super-ui-plus/types'
import type { TableColumnCtx } from "element-plus/es/components/table/src/table-column/defaults";
const data = reactive<any[]>([])

Array.from({ length: 50 }).forEach(() => {
  data.push({
    date: Date.now(),
    name: '王小虎',
    address: '上海市普陀区',
    address2: '金沙江路 1518 弄'
  })
})

const columns = reactive<ColumnProps<any>[]>([
  { prop: '$index', label: '序号', width: 80 },
  { prop: 'date', label: '日期', width: 200 },
  { prop: 'name', label: '姓名', width: 200 },
  { prop: 'address', label: '居住地址' },
  { prop: 'address2', label: '具体地址' },
])

// 列合并
interface SpanMethodProps {
  row: any;
  column: TableColumnCtx<any>;
  rowIndex: number;
  columnIndex: number;
}
const objectSpanMethod = ({ rowIndex, columnIndex }: SpanMethodProps) => {
  // 行合并
  if (rowIndex % 2 === 0) {
    if (columnIndex === 3) { // 合并第 3 列和第 4 列
      return [1, 2]
    } else if (columnIndex === 4) { // 被合并的列需要返回0
      return [0, 0]
    }
  }
  
  // 列合并
  if (columnIndex === 2) {
    if (rowIndex % 2 === 0) return { rowspan: 2, colspan: 1 };
    else return { rowspan: 0, colspan: 0 };
  }
};
</script>

编辑表格

共有三种编辑表格方式:双击编辑/行编辑/列编辑
想要启用单元格编辑必须设置单元格el和isEdit属性

<template>
  <div>
    <el-tabs type="border-card">
      <el-tab-pane label="双击编辑">
        设置ifDblclick属性开启双击编辑功能
        <SuperProTable
          ref="proTable"
          :columns="columns"
          :data="data"
          :ifDblclick="true"
        ></SuperProTable>
      </el-tab-pane>
      <el-tab-pane label="行编辑">
        需要为每行数据内添加_edit属性,值为true时为可编辑行
        <SuperProTable ref="proTable" :columns="columns2" :data="data2">
          <template #operation="scope">
            <el-button type="primary" link @click="() => scope.row._edit = true">编辑</el-button>
            <el-button type="primary" link @click="() => scope.row._edit = false">完成</el-button>
          </template>
        </SuperProTable>
      </el-tab-pane>
      <el-tab-pane label="列编辑">
        为需要编辑的列添加 edit 属性,并设置为 true,即可开启编辑功能
        <SuperProTable ref="proTable" :columns="columns3" :data="data"></SuperProTable>
      </el-tab-pane>
    </el-tabs>
  </div>
</template>

<script lang="ts" setup>
import { reactive } from 'vue'
import { ElTabs, ElTabPane } from 'element-plus'
import type { ColumnProps } from '@super-ui-plus/types'

const data = reactive<any[]>([
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
])

const columns = reactive<ColumnProps<any>[]>([
  { prop: '$index', label: '序号', width: 80 },
  { prop: 'date', label: '日期', width: 200 },
  { prop: 'name', label: '姓名(可编辑)', el: 'ElInput', isEdit: true },
  { prop: 'address', label: '居住地址' },
])

const data2 = reactive<any[]>([
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
    _edit: false,
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
    _edit: false,
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
    _edit: false,
  },
])

const columns2 = reactive<ColumnProps<any>[]>([
  { prop: '$index', label: '序号', width: 80 },
  { prop: 'date', label: '日期', width: 200, el: 'ElInput', isEdit: true },
  { prop: 'name', label: '姓名', el: 'ElInput', isEdit: true },
  { prop: 'address', label: '居住地址', el: 'ElInput', isEdit: true },
  { prop: 'operation', label: '操作', fixed: 'right' },
])

const columns3 = reactive<ColumnProps<any>[]>([
  { prop: '$index', label: '序号', width: 80 },
  { prop: 'date', label: '日期', width: 200 },
  { prop: 'name', label: '姓名', el: 'ElInput', isEdit: true, edit: true },
  { prop: 'address', label: '居住地址' },
])
</script>

编辑表格校验方法

和在布局表单中一样,通过 required 或 formItemProps:{rules: [验证规则]} 进行校验
可以调用表格的validateTableForm方法进行手动校验

<template>
  <div>
    <el-tabs type="border-card">
      <el-tab-pane label="双击编辑">
        <SuperProTable
          ref="proTable"
          :columns="columns"
          :data="data"
          :ifDblclick="true"
        ></SuperProTable>
      </el-tab-pane>
      <el-tab-pane label="行编辑">
        <SuperProTable ref="proTable2" :columns="columns2" :data="data2">
          <template #operation="scope">
            <el-button
              v-if="!scope.row._edit"
              type="primary"
              link
              @click="() => (scope.row._edit = true)"
            >
              编辑
            </el-button>
            <el-button v-else type="primary" link @click="handleSuccess(scope)">完成</el-button>
          </template>
        </SuperProTable>
      </el-tab-pane>
      <el-tab-pane label="列编辑">
        <el-button type="primary" @click="() => (colEdit = !colEdit)">
          {{ colEdit ? '保存' : '编辑' }}
        </el-button>
        <SuperProTable ref="proTable" :columns="columns3" :data="data"></SuperProTable>
      </el-tab-pane>
    </el-tabs>
  </div>
</template>

<script lang="ts" setup>
import { ref, reactive, useTemplateRef } from 'vue'
import { ElTabs, ElTabPane } from 'element-plus'
import type { ColumnProps } from '@super-ui-plus/types'

const data = reactive<any[]>([
  {
    date: Date.now(),
    name: '张三',
    number1: 10,
  },
  {
    date: Date.now(),
    name: '张三',
    number1: 10,
  },
  {
    date: Date.now(),
    name: '张三',
    number1: 10,
  },
])

const columns = reactive<ColumnProps<any>[]>([
  { prop: '$index', label: '序号', width: 80 },
  { prop: 'date', label: '日期', width: 200 },
  { prop: 'name', label: '姓名(可编辑)', el: 'ElInput', isEdit: true, required: true },
  {
    prop: 'number1',
    label: '数值(可编辑)',
    el: 'ElInput',
    isEdit: true,
    formItemProps: {
      rules: [
        {
          validator: (_rule, value, callback) => {
            if (Number(value) > 10) {
              callback()
            } else {
              callback('输入值不能小于10')
            }
          },
          trigger: 'change',
        },
      ],
    },
  },
])

const data2 = reactive<any[]>([
  {
    date: Date.now(),
    name: '张三',
    number1: 10,
    _edit: false,
  },
  {
    date: Date.now(),
    name: '张三',
    number1: 10,
    _edit: false,
  },
  {
    date: Date.now(),
    name: '张三',
    number1: 10,
    _edit: false,
  },
])

const columns2 = reactive<ColumnProps<any>[]>([
  { prop: '$index', label: '序号', width: 80 },
  { prop: 'date', label: '日期', width: 200, el: 'ElInput', isEdit: true },
  { prop: 'name', label: '姓名(可编辑)', el: 'ElInput', isEdit: true, required: true },
  {
    prop: 'number1',
    label: '数值(可编辑)',
    el: 'ElInput',
    isEdit: true,
    formItemProps: {
      rules: [
        {
          validator: (_rule, value, callback) => {
            if (Number(value) > 10) {
              callback()
            } else {
              callback('输入值不能小于10')
            }
          },
          trigger: 'change',
        },
      ],
    },
  },
  { prop: 'operation', label: '操作', fixed: 'right' },
])

const proTable2Ref = useTemplateRef('proTable2')
const handleSuccess = async (scope: any) => {
  await proTable2Ref.value.validateTableForm(scope.$index)
  scope.row._edit = false
}

const colEdit = ref<boolean>(false)
const columns3 = reactive<ColumnProps<any>[]>([
  { prop: '$index', label: '序号', width: 80 },
  { prop: 'date', label: '日期', width: 200 },
  {
    prop: 'name',
    label: '姓名(可编辑)',
    el: 'ElInput',
    isEdit: true,
    required: true,
    edit: colEdit
  },
  {
    prop: 'number1',
    label: '数值(可编辑)',
    el: 'ElInput',
    isEdit: true,
    edit: colEdit,
    formItemProps: {
      rules: [
        {
          validator: (_rule, value, callback) => {
            if (Number(value) > 10) {
              callback()
            } else {
              callback('输入值不能小于10')
            }
          },
          trigger: 'change',
        },
      ],
    },
  },
])
</script>

表格操作按钮

使用operation插槽来实现

<template>
  <div>
    <SuperProTable ref="proTable" :columns="columns" :data="data">
      <template #operation="scope">
        <el-button type="primary" link @click="() => ElMessage.success(`row:${JSON.stringify(scope.row)}`)">
          按钮1
        </el-button>
        <el-button type="primary" link @click="() => ElMessage.success('点击按钮2成功')">
          按钮2
        </el-button>
      </template>
    </SuperProTable>
  </div>
</template>

<script lang="ts" setup>
import { reactive } from 'vue'
import { ElMessage } from 'element-plus'
import type { ColumnProps } from '@super-ui-plus/types'

const data = reactive<any[]>([
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
])

const columns = reactive<ColumnProps<any>[]>([
  { prop: '$index', label: '序号', width: 80 },
  { prop: 'date', label: '日期' },
  { prop: 'name', label: '姓名' },
  { prop: 'address', label: '居住地址' },
  { prop: 'operation', label: '操作', fixed: 'right' },
])
</script>

表格头部操作按钮插槽

toolButton可控制右侧功能按钮的显示隐藏:传true则显示,false则隐藏,传数组则显示指定的功能按钮,比如['refresh']就只显示刷新按钮
tableHeader插槽可以自定义左侧内容

<template>
  <div>
    <SuperProTable ref="proTable" :columns="columns" :data="data" :toolButton="['setting']">
      <template #tableHeader>
        <el-button type="primary" plain >导出用户数据</el-button>
        <el-button type="primary" plain>To 子集详情页面</el-button>
        <el-button type="danger" plain>批量删除用户</el-button>
      </template>
    </SuperProTable>
  </div>
</template>

<script lang="ts" setup>
import { reactive } from 'vue'
import { ElButton } from 'element-plus'
import type { ColumnProps } from '@super-ui-plus/types'

const data = reactive<any[]>([
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
])

const columns = reactive<ColumnProps<any>[]>([
  { prop: '$index', label: '序号', width: 80 },
  { prop: 'date', label: '日期', width: 200 },
  { prop: 'name', label: '姓名', width: 200 },
  { prop: 'address', label: '居住地址' },
])
</script>

使用搜索表格

搜索表格支持searchForm和proTable的所有选项
使用requestApi属性获取数据要求:接口返回正常数据格式:
分页: { data: { list: [...], total: ... } }
不分页: { data: [...] }

<template>
  <div>
    <SuperProTable
      ref="proTable"
      :field="field"
      :columns="columns"
      :requestApi="getData"
      showSearch
      :initParam="form"
      :dataCallback="dataCallback"
      @search="handleSearch"
    >
      <template #date>
        <ElInput v-model="form.date" placeholder="使用插槽自定义内容" clearable />
      </template>
      <template #gridSlotComponent>
        <SuperGrid :gap="[10, 20]">
          <SuperGridItem :span="4">
            <el-form-item label="活动时间:">
              <div class="flx-center">
                <el-date-picker
                  type="date"
                  placeholder="选择日期"
                  v-model="form.activeStart"
                  style="width: 100%"
                ></el-date-picker>
                <span class="line">-</span>
                <el-time-picker
                  placeholder="选择时间"
                  v-model="form.activeEnd"
                  style="width: 100%"
                ></el-time-picker>
              </div>
            </el-form-item>
          </SuperGridItem>
        </SuperGrid>
      </template>
    </SuperProTable>
  </div>
</template>

<script lang="tsx" setup>
import { reactive } from 'vue'
import { ElInput, ElMessage } from 'element-plus'
import { Search } from '@element-plus/icons-vue'
import type { ColumnProps } from '@super-ui-plus/types'

const data = reactive<any[]>([
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
    time: Date.now(),
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
])

const form = reactive<any>({
  name: '我是默认值',
  phone: '13211111',
  minAge: '',
  maxAge: '',
  date: '',
  activeStart: '',
  activeEnd: '',
})

// 搜索表单配置项
const field = [
  {
    label: '姓名',
    name: 'name',
    el: 'ElInput',
    formItemProps: {
      rules: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
    },
    componentProps: {
      placeholder: '请输入姓名',
      clearable: true,
    },
    scopedSlots: {
      prepend: () => (
        <el-icon>
          <Search />
        </el-icon>
      ),
      append: () => <el-button>按钮</el-button>,
    },
    tooltip: '这是一个提示信息',
    span: 2,
  },
  {
    label: '手机号',
    name: 'phone',
    el: 'ElInput',
    componentProps: {
      placeholder: '请输入手机号',
      clearable: true,
    },
    required: true,
    valueType: 'phone',
    span: 2,
  },
  {
    label: '年龄',
    name: 'age',
    el: 'ElInput',
    componentProps: {
      placeholder: '请输入',
      clearable: true,
    },
    render: ({ searchParam }: any) => {
      // 普通v-model但无法使用修饰符
      return (
        <div class="flx-center">
          <ElInput v-model={searchParam.minAge} placeholder="最小年龄" />
          <span class="mr10 ml10">-</span>
          <ElInput v-model={searchParam.maxAge} placeholder="最大年龄" />
        </div>
      )
    },
    span: 2,
  },
  {
    label: '使用组件插槽',
    name: 'date',
    slotName: 'date',
    span: 2,
  },
  {
    label: '使用布局插槽',
    name: 'gridSlot',
    slotName: 'gridSlotComponent',
    span: 4,
  },
]

const columns = reactive<ColumnProps<any>[]>([
  { prop: '$index', label: '序号', width: 80 },
  { prop: 'date', label: '日期', width: 200 },
  { prop: 'name', label: '姓名', width: 200 },
  { prop: 'time', label: '秒' },
  { prop: 'address', label: '居住地址' },
])

const handleSearch = () => {
  ElMessage.success('搜索成功')
}

// 模拟网络请求
// 接口返回正常数据格式:
// 分页: { data: { list: [...], total: ... } }
// 不分页: { data: [...] }
const getData = (param: any) => {
  console.log(param, "param");
  
  // 第一种:接口返回正确的数据格式
  // return new Promise((resolve) => {
  //   setTimeout(() => {
  //     resolve({ data: { list: data, total: data.length } })
  //   }, 1000)
  // })

  // 第二种:使用回调函数返回正常的数据格式
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({ data: { listData: data, totalNumber: data.length} })
    }, 1000)
  })
}

// 修正数据格式
const dataCallback = (data: any) => {  
  return ({ list: data.listData, total: data.totalNumber })
}
</script>

隐藏搜索表单/表单选项/列数据

列设置isShow属性可以对列进行隐藏
showSearch 为true时显示搜索表单,默认为为false

<template>
  <div>
    表单数据: {{  form }}
    <SuperProTable
      ref="proSearchTable"
      :field="field"
      :columns="columns"
      :data="data"
      :showSearch="true"
      :initParam="initParam"
      @search="handleSearch"
    >
      <template #date="scope">
        <ElInput v-model="scope.searchParam.date" placeholder="使用插槽自定义内容" clearable />
      </template>
      <template #gridSlotComponent="scope">
        <SuperGrid :gap="[10, 20]">
          <SuperGridItem :span="4">
            <el-form-item label="活动时间:">
              <div class="flx-center">
                <el-date-picker
                  type="date"
                  placeholder="选择日期"
                  v-model="scope.searchParam.activeStart"
                  style="width: 100%"
                ></el-date-picker>
                <span class="line">-</span>
                <el-time-picker
                  placeholder="选择时间"
                  v-model="scope.searchParam.activeEnd"
                  style="width: 100%"
                ></el-time-picker>
              </div>
            </el-form-item>
          </SuperGridItem>
        </SuperGrid>
      </template>
    </SuperProTable>
  </div>
</template>

<script lang="tsx" setup>
import { reactive, useTemplateRef, computed } from 'vue'
import { ElInput, ElMessage } from 'element-plus'
import { Search } from '@element-plus/icons-vue'
import type { ColumnProps } from '@super-ui-plus/types'

const data = reactive<any[]>([
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
  {
    date: Date.now(),
    name: '张三',
    address: '北京',
  },
])

const initParam = reactive<any>({
  name: '',
  phone: '13211111',
  phone2: '',
  minAge: '',
  maxAge: '',
  date: '',
  activeStart: '',
  activeEnd: '',
})

const proSearchTableRef: any = useTemplateRef('proSearchTable')
const form = computed(() => proSearchTableRef.value?.searchParam)

// 搜索表单配置项
const field = [
  {
    label: '姓名',
    name: 'name',
    el: 'ElInput',
    formItemProps: {
      rules: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
    },
    componentProps: {
      placeholder: '请输入姓名',
      clearable: true,
    },
    scopedSlots: {
      prepend: () => (
        <el-icon>
          <Search />
        </el-icon>
      ),
      append: () => <el-button>按钮</el-button>,
    },
    tooltip: '这是一个提示信息',
    span: 2,
  },
  {
    label: '手机号',
    name: 'phone',
    el: 'ElInput',
    show: false,
    componentProps: {
      placeholder: '请输入手机号',
      clearable: true,
    },
    required: true,
    valueType: 'phone',
    span: 2,
  },
  {
    label: '手机号2',
    name: 'phone2',
    el: 'ElInput',
    show: () => !!form.value?.name,
    componentProps: {
      placeholder: '请输入手机号',
      clearable: true,
    },
    required: true,
    valueType: 'phone',
    span: 2,
  },
  {
    label: '年龄',
    name: 'age',
    el: 'ElInput',
    componentProps: {
      placeholder: '请输入',
      clearable: true,
    },
    render: ({ searchParam }: any) => {
      // 普通v-model但无法使用修饰符
      return (
        <div class="flx-center">
          <ElInput v-model={searchParam.minAge} placeholder="最小年龄" />
          <span class="mr10 ml10">-</span>
          <ElInput v-model={searchParam.maxAge} placeholder="最大年龄" />
        </div>
      )
    },
    span: 2,
  },
  {
    label: '使用组件插槽',
    name: 'date',
    slotName: 'date',
    span: 2,
  },
  {
    label: '使用布局插槽',
    name: 'gridSlot',
    slotName: 'gridSlotComponent',
    span: 4,
  },
]

const columns = reactive<ColumnProps<any>[]>([
  { prop: '$index', label: '序号', width: 80 },
  { prop: 'date', label: '日期', width: 200, isShow: false },
  { prop: 'name', label: '姓名', width: 200 },
  { prop: 'address', label: '居住地址' },
])

const handleSearch = () => {
  ElMessage.success('搜索成功')
}
</script>

隐藏表格分页

设置pagination为false时隐藏分页

<template>
  <div>
    <SuperProTable
      ref="proTable"
      :columns="columns"
      :data="data"
      :pagination="false"
      height="300px"
    ></SuperProTable>
  </div>
</template>

<script lang="ts" setup>
import { reactive } from 'vue'
import type { ColumnProps } from '@super-ui-plus/types'

const data = reactive<any[]>([])

Array.from({ length: 100 }).forEach((_, index) => {
  data.push({
    date: Date.now(),
    name: '张三' + index,
    address: '北京',
  },)
})

const columns = reactive<ColumnProps<any>[]>([
  { prop: '$index', label: '序号', width: 80 },
  { prop: 'date', label: '日期', width: 200 },
  { prop: 'name', label: '姓名', width: 200 },
  { prop: 'address', label: '居住地址' },
])
</script>

API

table Props

参数说明类型可选值默认值
columns列配置项ColumnProps[]--
data静态 table data 数据 any[]--
requestApi请求表格数据的 api ==> 非必传(params: any) => Promise<any>--
requestAuto是否自动执行请求booleantrue/falsetrue
requestError表格 api 请求错误监听回调函数(params: any) => void--
dataCallback返回数据的回调函数,可以对数据进行处理(data: any) => any--
pagination是否需要分页组件booleantrue/falsetrue
initParam初始化请求参数object--
border是否带有纵向边框booleantrue/falsetrue
toolButton是否显示表格功能按钮array | boolean('refresh' | 'setting' | 'search')[] | booleantrue
rowKey行数据的 Key,用来优化 Table 的渲染; 在使用reserve-selection功能与显示树形数据时,该属性是必填的string--
showSummary是否在表格底部显示合计行booleantrue/falsefalse
sumText自定义合计行文本string-合计
sumNaNText自定义合计行文本string-N/A
ifDblclick是否开启双击单元格编辑booleantrue/falsefalse
align单元格对齐方式string-center
height表格高度string | number--
ifContinuousMultiple是否开启列表数据连续多选booleantrue/falsetrue
autoScroll分页自动滚动到首行booleantrue/falsetrue
showSearch是否显示搜索模块booleantrue/falsefalse
field搜索配置列formGridItemProps[]--

Column Props

参数说明类型可选值默认值
type列类型enumenum-
tag是否是标签展示function(scope: RenderScope<T>) => any -
isShow是否显示booleantrue/falsetrue
isSetting是否在 ColSetting 中可配置booleantrue/falsetrue
isEdit是否可编辑booleantrue/falsefalse
edit编辑状态booleantrue/falsefalse
required是否必填booleantrue/falsefalse
valueType内置验证规则类型string--
formItemProps透传 el-form-item 属性Partial<FormItemProps>--
el渲染组件名称strigng--
enum枚举字典数据EnumProps[]--
headerRender自定义表头内容渲染(tsx语法)(scope: HeaderRenderScope<T>) => VNodeHeaderRenderScope-
render自定义单元格内容渲染(tsx语法)(scope: RenderScope<T>) => VNode | string--
format内置格式化方式((value: any) => string) | string;--
sumFilter自定义合计内容(value: any, param: SummaryMethodProps) => stringSummaryMethodProps-
sumDataPrefix合计数据前缀strigng--
_children多级表头ColumnProps<T>[]--
align单元格对齐方式string-center

table Slots

插槽名说明
default表格默认内容插槽
tableHeader表格上方插槽
toolButton右侧工具扩展插槽
append插入表格最后一行之后的插槽
pagination分页组件插槽
searchForm搜索表单插槽
formGridSlots/formGridItemSlots搜索表单元素内容插槽

table Colum Slots

插槽名说明
header自定义表头的内容
expand展开列的自定义内容