Skip to content

Table 表格

gi-table 组件是基于 Element Plus 的 el-tableel-pagination 组件封装的高级表格组件,提供了更便捷的配置方式和增强的功能,包括动态列配置、自定义渲染、嵌套列支持、分页集成等

基础用法

暂无数据
  • 1
共 0 条
查看代码
vue
<template>
  <gi-page-layout bordered style="height: 500px">
    <template #tool>
      <el-row justify="space-between" class="gi-tool gi-w-full">
        <el-space warp>
          <gi-button type="add"></gi-button>
          <gi-button type="delete"></gi-button>
        </el-space>
        <el-space warp>
          <el-input v-model="queryParams.keyword" placeholder="搜索姓名或地址" clearable style="width: 200px" />
          <ElButton type="primary" @click="search">搜索</ElButton>
        </el-space>
      </el-row>
    </template>
    <gi-table v-loading="loading" :columns="columns" :data="tableData" :pagination="pagination">
      <template #action="scope">
        <el-space>
          <ElButton type="primary" size="small" @click="onEdit(scope.row)">编辑</ElButton>
          <ElButton type="danger" size="small">删除</ElButton>
        </el-space>
      </template>
    </gi-table>
  </gi-page-layout>
</template>

<script lang="ts" setup>
import type { TableColumnItem } from 'gi-component'
import { getUserList } from '@docs/_apis/mockTable'
import { useTable } from '@docs/_hooks'
import { ElButton, ElMessage, ElTag } from 'element-plus'
import { h, reactive } from 'vue'

const columns: TableColumnItem[] = [
  { type: 'selection', width: 55, align: 'center', fixed: 'left' },
  { type: 'index', label: '序号', width: 60, align: 'center' },
  {
    prop: 'name',
    label: '姓名',
    width: 100,
    align: 'center',
    showOverflowTooltip: true
  },
  { prop: 'age', label: '年龄', width: 60, align: 'center' },
  {
    prop: 'sex',
    label: '性别',
    width: 80,
    align: 'center',
    render: ({ row }) => {
      return h(
        ElTag,
        { type: row.sex === '男' ? 'primary' : 'danger', size: 'small' },
        { default: () => row.sex }
      )
    }
  },
  {
    prop: 'address',
    label: '地址'
  },
  { prop: 'remark', label: '描述', width: 150, showOverflowTooltip: true },
  {
    prop: 'action',
    label: '操作',
    width: 140,
    align: 'center',
    slotName: 'action',
    fixed: 'right'
  }
]

const queryParams = reactive({
  keyword: ''
})

const { tableData, getTableData, pagination, search, refresh, loading } = useTable((p) => getUserList({ ...p, ...queryParams }), {
  onSuccess: () => {
    // ElMessage.success(`页码${pagination.currentPage}, 页数${pagination.pageSize}条--数据成功加载`);
  }
})

// 编辑操作
function onEdit(scope: any) {
  ElMessage.success(`编辑 ${scope.row.name}`)
}
</script>

<style lang="scss" scoped></style>

表头搜索

本示例只提供技巧参考,实际项目请根据自身需求进行封装useTableHeaderSearch函数hooks

暂无数据
  • 1
共 0 条
{}
查看代码
vue
<template>
  <gi-page-layout bordered style="height: 500px">
    <template #tool>
      <el-row justify="space-between" class="gi-tool gi-w-full">
        <el-space warp>
          <gi-button type="add"></gi-button>
          <gi-button type="delete"></gi-button>
        </el-space>
        <el-space warp>
          <el-input v-model="queryParams.keyword" placeholder="搜索姓名或地址" clearable style="width: 200px" />
          <ElButton type="primary" @click="search">搜索</ElButton>
        </el-space>
      </el-row>
    </template>
    <gi-table v-loading="loading" :columns="columns" :data="tableData" :pagination="pagination" border>
      <template #action="scope">
        <el-space>
          <ElButton type="primary" size="small" @click="onEdit(scope)">编辑</ElButton>
          <ElButton type="danger" size="small">删除</ElButton>
        </el-space>
      </template>
    </gi-table>
    <pre class="doc-pre">{{ headerParams }}</pre>
  </gi-page-layout>
</template>

<script lang="ts" setup>
import type { UserItem } from '@docs/_apis/mockTable'
import type { TableColumnItem } from 'gi-component'
import { getUserList } from '@docs/_apis/mockTable'
import { useTable } from '@docs/_hooks'
import { ElButton, ElMessage, ElTag } from 'element-plus'
import { h, reactive } from 'vue'
import { useTableHeaderSearch } from './components/useTableHeaderSearch'

const queryParams = reactive({
  keyword: ''
})

const { tableData, getTableData, pagination, search, refresh, loading } = useTable((p) => getUserList({ ...p, ...queryParams }), {
  onSuccess: () => {
    // ElMessage.success(`页码${pagination.currentPage}, 页数${pagination.pageSize}条--数据成功加载`);
  }
})

const { headerParams, createTableHeader } = useTableHeaderSearch({ search: () => search() })

const columns: TableColumnItem<UserItem>[] = [
  { type: 'selection', width: 55, align: 'center', fixed: 'left' },
  { type: 'index', label: '序号', width: 60, align: 'center' },
  {
    prop: 'name',
    label: '姓名',
    width: 100,
    align: 'center',
    showOverflowTooltip: true,
    renderHeader: () => createTableHeader({ type: 'input', label: '姓名', field: 'name' })
  },
  { prop: 'age', label: '年龄', width: 60, align: 'center' },
  {
    prop: 'sex',
    label: '性别',
    width: 80,
    align: 'center',
    render: ({ row }) => {
      return h(
        ElTag,
        { type: row.sex === '男' ? 'primary' : 'danger', size: 'small' },
        { default: () => row.sex }
      )
    },
    renderHeader: () => createTableHeader({ type: 'checkbox-group', label: '性别', field: 'sex' })
  },
  {
    prop: 'address',
    label: '地址',
    children: [
      { prop: 'city', label: '城市', width: 100 },
      { prop: 'district', label: '区县', width: 100 }
    ]
  },
  { prop: 'remark', label: '描述', width: 150, showOverflowTooltip: true },
  {
    prop: 'action',
    label: '操作',
    width: 140,
    align: 'center',
    slotName: 'action',
    fixed: 'right'
  }
]

// 编辑操作
function onEdit(scope: any) {
  ElMessage.success(`编辑 ${scope.row.name}`)
}
</script>

<style lang="scss" scoped></style>
useTableHeaderSearch.ts
ts
import { h, reactive } from 'vue'
import HeaderCheckboxGroup from './HeaderCheckboxGroup.vue'
import HeaderInput from './HeaderInput.vue'

export function useTableHeaderSearch(options: { search: () => void }) {
  const headerParams = reactive({} as Record<string, any>)

  function createTableHeader(params: { type: 'input' | 'checkbox-group', label: string, field: string }) {
    if (params.type === 'input') {
      return h(HeaderInput, { headerParams, label: params.label, field: params.field, onConfirm: () => options.search() })
    }
    if (params.type === 'checkbox-group') {
      return h(HeaderCheckboxGroup, { headerParams, label: params.label, field: params.field, onConfirm: () => options.search() })
    }
    return h('div', {}, params.label)
  }

  return {
    headerParams,
    createTableHeader
  }
}
HeaderInput.vue
vue
<template>
  <el-popover v-model:visible="visible" placement="bottom" :width="200">
    <template #reference>
      <HeaderLabel :label="props.label" :actived="!!props.headerParams[props.field]" @click="visible = true">
      </HeaderLabel>
    </template>
    <el-input v-model="props.headerParams[props.field]" :placeholder="`输入${props.label}查询`" clearable
      size="small"></el-input>
    <el-row justify="end" style="margin-top: 10px">
      <el-space>
        <el-button size="small" @click="visible = false">取消</el-button>
        <el-button type="primary" size="small" @click="onConfirm">确定</el-button>
      </el-space>
    </el-row>
  </el-popover>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import HeaderLabel from './HeaderLabel.vue'

interface Props {
  label: string
  field: string
  headerParams: Record<string, any>
}
const props = withDefaults(defineProps<Props>(), {})

const emit = defineEmits<{
  (e: 'confirm'): void
}>()

const visible = ref(false)
function onConfirm() {
  emit('confirm')
  visible.value = false
}
</script>
HeaderCheckboxGroup.vue
vue
<template>
  <el-popover :visible="visible" placement="bottom" :width="200" :popper-style="{ width: '140px', minWidth: '0px' }">
    <template #reference>
      <HeaderLabel :label="props.label" :actived="!!props.headerParams[props.field]?.length" @click="visible = true">
      </HeaderLabel>
    </template>
    <el-checkbox-group v-model="props.headerParams[props.field]" :options="options" />
    <el-row justify="end" style="margin-top: 10px">
      <el-space>
        <el-button size="small" @click="visible = false">取消</el-button>
        <el-button type="primary" size="small" @click="onConfirm">确定</el-button>
      </el-space>
    </el-row>
  </el-popover>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import HeaderLabel from './HeaderLabel.vue'

interface Props {
  label: string
  field: string
  headerParams?: Record<string, any>
}
const props = withDefaults(defineProps<Props>(), {
  headerParams: () => ({})
})

const emit = defineEmits<{
  (e: 'confirm'): void
}>()

const visible = ref(false)
const options = [
  { label: '男', value: '1' },
  { label: '女', value: '2' }
]
function onConfirm() {
  emit('confirm')
  visible.value = false
}
</script>

<style lang="scss" scoped>
:deep(.el-checkbox) {
  display: flex;
  margin-right: 0;
}
</style>

API 使用说明

组件属性

属性名类型默认值说明
columnsTableColumnItem[][]表格列配置数组
dataany[]-表格数据
paginationPartial<PaginationProps> | boolean{}分页配置
其他属性--支持 Element Plus Table 组件的所有属性

TableColumnItem 接口

TableColumnItem 接口继承自 Element Plus 的 TableColumnInstance['$props'],并扩展了以下属性:

属性名类型说明
slotNamestring用于自定义列内容的插槽名称
childrenTableColumnItem[]子列配置,用于创建嵌套表头
render(scope: TableColumnCtx<any>) => VNode | VNode[] | string自定义渲染函数,用于动态生成单元格内容
其他属性-支持 Element Plus TableColumn 的所有属性

Pagination 配置

pagination 属性支持 Element Plus Pagination 组件的所有配置项,常用配置如下:

事件

支持 Element Plus Table 组件的所有事件。

插槽

除了通过 slotName 属性定义的自定义列插槽外,还支持 Element Plus Table 组件的所有作用域插槽。