Skip to content

SimpleTable 简单表格

SimpleTable 是一款非常轻量的表格组件,只使用HTML table实现所有功能。

TIP

组件需要包裹 <client-only></client-only> 标签,当用在 SSR (eg: Nuxt) 和 SSG (eg: VitePress)。

WARNING

Vitepress默认主题对组件样式有一定干扰,但不影响功能。

基础样式

文本溢出设置参考

用户名
年龄
单位
简介
操作
柏庐
20
某个公司
来自UED的设计师来自UED的设计来自UED的设计师来自UED的设计来自UED的设计师来自UED的设计来自UED的设计师来自UED的设计来自UED的设计师来自UED的设计来自UED的设计师来自UED的设计
军结
22
某个公司
经验丰富的前端工程师
钞洋
28
某个公司
90后交互设计师
示例代码
vue
<template>
  <epp-simple-table :cols="cols" :data="tableData" @row-click="rowClicked" @cell-click="cellClicked">
    <template #firstCol>
      <el-checkbox v-model="selectedAll" :indeterminate="isIndeterminate" @change="selectAll" />
    </template>
    <template #tableIndex="{ row }">
      <el-checkbox v-model="selectedRows" :value="row.id" @change="selectRow(row.id)">{{ '' }}</el-checkbox>
    </template>

    <template #handle>
      <a>修改</a>
    </template>
  </epp-simple-table>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import type { ColumnType } from 'element-plus-plus';

const selectedAll = ref(false);
const selectedRows = ref<number[]>([]);
const isIndeterminate = ref(false);

const tableData = ref([
  {
    id: 1,
    name: '柏庐',
    sex: '女',
    org: '某个公司',
    des: '来自UED的设计师来自UED的设计来自UED的设计师来自UED的设计来自UED的设计师来自UED的设计来自UED的设计师来自UED的设计来自UED的设计师来自UED的设计来自UED的设计师来自UED的设计',
    otherInfo: {
      age: 20,
    },
  },
  {
    id: 2,
    name: '军结',
    sex: '男',
    org: '某个公司',
    des: '经验丰富的前端工程师',
    otherInfo: {
      age: 22,
    },
  },
  {
    id: 3,
    name: '钞洋',
    sex: '男',
    org: '某个公司',
    des: '90后交互设计师',
    otherInfo: {
      age: 28,
    },
  },
]);
const cols = ref([
  { title: '#', slotName: 'tableIndex', headerSlotName: 'firstCol', width: '3em' },
  { title: '用户名', prop: 'name' },
  { title: '年龄', prop: 'otherInfo.age' },
  { title: '单位', prop: 'org', align: 'center' },
  {
    title: '简介',
    prop: 'des',
    align: 'center',
    showTooltip: true,
    width: '40%',
    tooltipProps: { width: '200px', popperClass: 'test-tip' },
  },
  { title: '操作', slotName: 'handle', align: 'center' },
]);

const selectAll = () => {
  if (selectedAll.value) {
    selectedRows.value.splice(0, selectedRows.value.length);
    selectedRows.value.push(...tableData.value.map((d) => d.id));
    isIndeterminate.value = false;
  } else {
    selectedRows.value.splice(0, selectedRows.value.length);
  }
};
const selectRow = () => {
  selectedAll.value = selectedRows.value.length === tableData.value.length;
  if (selectedRows.value.length > 0 && selectedAll.value == false) {
    isIndeterminate.value = true;
  } else {
    isIndeterminate.value = false;
  }
};
const rowClicked = (row: Record<string, any>, rowIndex: number, event: Event) => {
  console.log('rowClicked', row, rowIndex, event);
};
const cellClicked = (row: Record<string, any>, col: ColumnType, rowIndex: number, colIndex: number, event: Event) => {
  console.log('cellClicked', row, col, rowIndex, colIndex, event);
};
</script>

边框样式

border 属性可为表格加上设置边框样式

#
用户名
性别
单位
简介
操作
1
王二麻子
某个公司
来自中国南方的温暖城市!
2
李四
某个公司
来自中国
3
张三
某个公司
来自中国北方的寒冷的城市!
示例代码
vue
<template>
  <el-select v-model="value" clearable placeholder="请选择" class="w-200 m-b-lg">
    <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
  </el-select>

  <epp-simple-table :cols="cols" :data="tableData" :border="value" padding="0">
    <template #tableIndex="{ rowIndex }">
      <span>{{ rowIndex + 1 }}</span>
    </template>
    <template #handle>
      <a>修改</a>
    </template>
  </epp-simple-table>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const tableData = ref([
  {
    id: 1,
    name: '王二麻子',
    sex: '男',
    org: '某个公司',
    des: '来自中国南方的温暖城市!',
  },
  { id: 2, name: '李四', sex: '男', org: '某个公司', des: '来自中国' },
  {
    id: 3,
    name: '张三',
    sex: '男',
    org: '某个公司',
    des: '来自中国北方的寒冷的城市!',
  },
]);
const cols = ref([
  { title: '#', slotName: 'tableIndex' },
  { title: '用户名', prop: 'name' },
  { title: '性别', prop: 'sex' },
  { title: '单位', prop: 'org' },
  { title: '简介', prop: 'des' },
  { title: '操作', slotName: 'handle', align: 'center' },
]);
const options = ref([
  {
    value: 'borderless',
    label: 'borderless',
  },
  {
    value: 'border-x',
    label: 'border-x',
  },
  {
    value: 'border-y',
    label: 'border-y',
  },
  {
    value: 'bordered',
    label: 'bordered',
  },
]);
const value = ref('borderless');
</script>

间距设置

padding 属性可为表格加上设置不同的间距尺寸, 同时cell-padding 可设置TD的间距尺寸

#
用户名
性别
单位
简介
操作
1
王二麻子
某个公司
来自中国南方的温暖城市!
2
李四
某个公司
来自中国
3
张三
某个公司
来自中国北方的寒冷的城市!
示例代码
vue
<template>
  <el-select v-model="value" clearable placeholder="请选择表格填充" class="m-b-md w-200">
    <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
  </el-select>

  <el-select v-model="value2" clearable placeholder="请选择单元格填充" class="m-l-md m-b-md w-200">
    <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
  </el-select>

  <epp-simple-table :cols="cols" :data="tableData" border="border-x" :padding="value" :cell-padding="value2">
    <template #tableIndex="{ rowIndex }">
      <span>{{ rowIndex + 1 }}</span>
    </template>
    <template #handle>
      <el-button link type="primary">修改</el-button>
    </template>
  </epp-simple-table>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const tableData = ref([
  {
    id: 1,
    name: '王二麻子',
    sex: '男',
    org: '某个公司',
    des: '来自中国南方的温暖城市!',
  },
  { id: 2, name: '李四', sex: '男', org: '某个公司', des: '来自中国' },
  {
    id: 3,
    name: '张三',
    sex: '男',
    org: '某个公司',
    des: '来自中国北方的寒冷的城市!',
  },
]);
const cols = ref([
  { title: '#', slotName: 'tableIndex' },
  { title: '用户名', prop: 'name' },
  { title: '性别', prop: 'sex' },
  { title: '单位', prop: 'org' },
  { title: '简介', prop: 'des' },
  { title: '操作', slotName: 'handle', align: 'center' },
]);
const options = ref([
  {
    value: '0',
    label: 'none',
  },
  {
    value: '8px',
    label: '8px',
  },
  {
    value: '12px',
    label: '12px',
  },
  {
    value: '16px',
    label: '16px',
  },
  {
    value: '20px',
    label: '20px',
  },
  {
    value: '24px',
    label: '24px',
  },
]);
const value = ref('0');
const value2 = ref('0');
</script>

悬停样式 Hover

hover 属性可以在悬停在某一行时,呈现背景色。

#
用户名
性别
单位
简介
操作
1
王二麻子
某个公司
来自中国南方的温暖城市!
2
李四
某个公司
来自中国
3
张三
某个公司
来自中国北方的寒冷的城市!
示例代码
vue
<template>
  <epp-simple-table :cols="cols" :data="tableData" cross-hover hover>
    <template #tableIndex="{ rowIndex }">
      <span>{{ rowIndex + 1 }}</span>
    </template>
    <template #handle>
      <el-button link type="primary">修改</el-button>
    </template>
  </epp-simple-table>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const tableData = ref([
  {
    id: 1,
    name: '王二麻子',
    sex: '男',
    org: '某个公司',
    des: '来自中国南方的温暖城市!',
  },
  { id: 2, name: '李四', sex: '男', org: '某个公司', des: '来自中国' },
  {
    id: 3,
    name: '张三',
    sex: '男',
    org: '某个公司',
    des: '来自中国北方的寒冷的城市!',
  },
]);
const cols = ref([
  { title: '#', slotName: 'tableIndex' },
  { title: '用户名', prop: 'name' },
  { title: '性别', prop: 'sex' },
  { title: '单位', prop: 'org' },
  { title: '简介', prop: 'des' },
  { title: '操作', slotName: 'handle', align: 'center' },
]);
</script>

条纹样式

stripe属性可以创建条纹的表格,以便区分出不同行的数据。

#
用户名
性别
单位
简介
操作
1
王二麻子
某个公司
来自中国南方的温暖城市!
2
李四
某个公司
来自中国
3
张三
某个公司
来自中国北方的寒冷的城市!
stripe 还接收 even 或者 odd 属性来设置条纹显示的顺序。默认为 odd 奇数
vue
<template>
  <epp-simple-table :cols="cols" :data="tableData" stripe>
    <template #tableIndex="{ rowIndex }">
      <span>{{ rowIndex + 1 }}</span>
    </template>
    <template #handle>
      <el-button link type="primary">修改</el-button>
    </template>
  </epp-simple-table>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const tableData = ref([
  {
    id: 1,
    name: '王二麻子',
    sex: '男',
    org: '某个公司',
    des: '来自中国南方的温暖城市!',
  },
  { id: 2, name: '李四', sex: '男', org: '某个公司', des: '来自中国' },
  {
    id: 3,
    name: '张三',
    sex: '男',
    org: '某个公司',
    des: '来自中国北方的寒冷的城市!',
  },
]);
const cols = ref([
  { title: '#', slotName: 'tableIndex' },
  { title: '用户名', prop: 'name' },
  { title: '性别', prop: 'sex' },
  { title: '单位', prop: 'org' },
  { title: '简介', prop: 'des' },
  { title: '操作', slotName: 'handle', align: 'center' },
]);
</script>

尺寸修饰

size 属性可以设置表格的尺寸。

#
用户名
性别
单位
简介
操作
1
王二麻子
某个公司
来自中国南方的温暖城市!
2
李四
某个公司
来自中国
3
张三
某个公司
来自中国北方的寒冷的城市!
示例代码
vue
<template>
  <el-select v-model="value" clearable placeholder="请选择" class="m-b-md w-200">
    <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
  </el-select>

  <epp-simple-table :cols="cols" :data="tableData" :size="value" class="borderless-last">
    <template #tableIndex="{ rowIndex }">
      <span>{{ rowIndex + 1 }}</span>
    </template>
    <template #handle>
      <a>修改</a>
    </template>
  </epp-simple-table>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const tableData = ref([
  {
    id: 1,
    name: '王二麻子',
    sex: '男',
    org: '某个公司',
    des: '来自中国南方的温暖城市!',
  },
  { id: 2, name: '李四', sex: '男', org: '某个公司', des: '来自中国' },
  {
    id: 3,
    name: '张三',
    sex: '男',
    org: '某个公司',
    des: '来自中国北方的寒冷的城市!',
  },
]);
const cols = ref([
  { title: '#', slotName: 'tableIndex' },
  { title: '用户名', prop: 'name' },
  { title: '性别', prop: 'sex' },
  { title: '单位', prop: 'org' },
  { title: '简介', prop: 'des' },
  { title: '操作', slotName: 'handle', align: 'center' },
]);
const options = ref([
  {
    value: 'sm',
    label: 'sm',
  },
  {
    value: 'md',
    label: 'md',
  },
  {
    value: 'lg',
    label: 'lg',
  },
]);
const value = ref('md');
</script>

拖拽改变列宽

resize 属性设置为 true,可以拖拽表格头的列,从而改变列宽。

#
用户名
性别
单位
简介
操作
1
王二麻子
某个公司
来自中国南方的温暖城市!
2
李四
某个公司
来自中国
3
张三
某个公司
来自中国北方的寒冷的城市!
示例代码
vue
<template>
  <epp-simple-table :cols="cols" :data="tableData" border="bordered" resize>
    <template #tableIndex="{ rowIndex }">
      <span>{{ rowIndex + 1 }}</span>
    </template>
    <template #handle>
      <a>修改</a>
    </template>
  </epp-simple-table>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const tableData = ref([
  {
    id: 1,
    name: '王二麻子',
    sex: '男',
    org: '某个公司',
    des: '来自中国南方的温暖城市!',
  },
  { id: 2, name: '李四', sex: '男', org: '某个公司', des: '来自中国' },
  {
    id: 3,
    name: '张三',
    sex: '男',
    org: '某个公司',
    des: '来自中国北方的寒冷的城市!',
  },
]);
const cols = ref([
  { title: '#', slotName: 'tableIndex', width: '4em' },
  { title: '用户名', prop: 'name', width: '8em' },
  { title: '性别', prop: 'sex', width: '4em' },
  { title: '单位', prop: 'org', width: '' },
  { title: '简介', prop: 'des', width: '' },
  { title: '操作', slotName: 'handle', align: 'center', width: '6em' },
]);
</script>

列表样式

list 可以将传统的表格呈现成列表的状态。

#
用户名
性别
单位
简介
操作
Briefcase
王二麻子
某个公司
来自中国南方的温暖城市!
ChartPie
李四
某个公司
来自中国
Archive
张三
某个公司
来自中国北方的寒冷的城市!
Archive
李四2
某个公司
来自中国
Archive
李四3
某个公司
来自中国
Archive
李四4
某个公司
来自中国
列表样式会为每一行表格加上圆角,你也可以自定义每一行的间距,例如:gap="var(--xs)"
vue
<template>
  <div style="background-color: #25303f; height: 240px; padding: 12px;">
    <el-scrollbar style="height: 200px">
      <epp-simple-table :cols="cols" :data="tableData" gap-y="8px" list fixed-header>
        <template #tableIndex="{ row }">
          {{ row.icon }}
        </template>
        <template #handle>
          <a>修改</a>
        </template>
      </epp-simple-table>
    </el-scrollbar>
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const tableData = ref([
  {
    id: 1,
    name: '王二麻子',
    sex: '男',
    org: '某个公司',
    des: '来自中国南方的温暖城市!',
    icon: 'Briefcase',
  },
  {
    id: 2,
    name: '李四',
    sex: '男',
    org: '某个公司',
    des: '来自中国',
    icon: 'ChartPie',
  },
  {
    id: 3,
    name: '张三',
    sex: '男',
    org: '某个公司',
    des: '来自中国北方的寒冷的城市!',
    icon: 'Archive',
  },
  { id: 4, name: '李四2', sex: '男', org: '某个公司', des: '来自中国', icon: 'Archive' },
  { id: 5, name: '李四3', sex: '男', org: '某个公司', des: '来自中国', icon: 'Archive' },
  { id: 6, name: '李四4', sex: '男', org: '某个公司', des: '来自中国', icon: 'Archive' },
]);
const cols = ref([
  { title: '#', slotName: 'tableIndex' },
  { title: '用户名', prop: 'name' },
  { title: '性别', prop: 'sex' },
  { title: '单位', prop: 'org' },
  { title: '简介', prop: 'des' },
  { title: '操作', slotName: 'handle', align: 'center' },
]);
</script>

固定表头

为 SimpleTable 组件加上 fixed-header 属性可以使表头固定在顶端。

#
用户名
性别
单位
简介
操作
1
王二麻子
某个公司
来自中国南方的温暖城市!
2
李四
某个公司
来自中国
3
张三
某个公司
来自中国北方的寒冷的城市!
4
李四2
某个公司
来自中国
5
李四3
某个公司
来自中国
6
李四4
某个公司
来自中国
示例代码
vue
<template>
  <div class="table-scroll" style="height: 200px">
    <epp-simple-table :cols="cols" :data="tableData" border="bordered" fixed-header>
      <template #tableIndex="{ rowIndex }">
        <span>{{ rowIndex + 1 }}</span>
      </template>
      <template #handle>
        <el-button link type="primary">修改</el-button>
      </template>
    </epp-simple-table>
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const tableData = ref([
  {
    id: 1,
    name: '王二麻子',
    sex: '男',
    org: '某个公司',
    des: '来自中国南方的温暖城市!',
  },
  { id: 2, name: '李四', sex: '男', org: '某个公司', des: '来自中国' },
  {
    id: 3,
    name: '张三',
    sex: '男',
    org: '某个公司',
    des: '来自中国北方的寒冷的城市!',
  },
  { id: 4, name: '李四2', sex: '男', org: '某个公司', des: '来自中国' },
  { id: 5, name: '李四3', sex: '男', org: '某个公司', des: '来自中国' },
  { id: 6, name: '李四4', sex: '男', org: '某个公司', des: '来自中国' },
]);
const cols = ref([
  { title: '#', slotName: 'tableIndex' },
  { title: '用户名', prop: 'name' },
  { title: '性别', prop: 'sex' },
  { title: '单位', prop: 'org' },
  { title: '简介', prop: 'des' },
  { title: '操作', slotName: 'handle', align: 'center' },
]);
</script>

固定列

  • 为某一列增加 fixed 属性可以使它固定,同时你可以传递 left right 来控制它固定在什么地方。例如 fixed: 'left'
  • fixed 属性还可以为 object 类型,详细控制 fixed 的距离。在 fixedobject 类型时,distance 字段可以设置成 auto,这样将会根据列宽自动计算应固定的距离。
  • 建议使用时,distance 要么都设置具体数值,要么都设置成auto,混用可能会导致计算错误。
序号
姓名
性别
工号
职级
司龄
字段1
字段2
右自动固定
描述
单位
操作
1
王二麻子
478343
P8
10
测试字段1
测试字段2
测试字段3
来自中国南方的温暖城市!
某个公司
2
李四
238343
P6
3
测试字段1
测试字段2
测试字段3
来自中国
某个公司
3
张三
178343
P7
5
测试字段1
测试字段2
测试字段3
来自中国北方的寒冷的城市!
某个公司
示例代码
vue
<template>
  <div class="table-scroll scroll-column">
    <epp-simple-table :cols="cols" :data="tableData" border="border-x">
      <template #tableIndex="{ rowIndex }">
        <span>{{ rowIndex + 1 }}</span>
      </template>
      <template #handle>
        <el-button link type="primary">修改</el-button>
      </template>
    </epp-simple-table>
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const tableData = ref([
  {
    id: 1,
    name: '王二麻子',
    sex: '男',
    org: '某个公司',
    des: '来自中国南方的温暖城市!',
    no: '478343',
    level: 'P8',
    years: 10,
    field1: '测试字段1',
    field2: '测试字段2',
    field3: '测试字段3',
  },
  {
    id: 2,
    name: '李四',
    sex: '男',
    org: '某个公司',
    des: '来自中国',
    no: '238343',
    level: 'P6',
    years: 3,
    field1: '测试字段1',
    field2: '测试字段2',
    field3: '测试字段3',
  },
  {
    id: 3,
    name: '张三',
    sex: '男',
    org: '某个公司',
    des: '来自中国北方的寒冷的城市!',
    no: '178343',
    level: 'P7',
    years: 5,
    field1: '测试字段1',
    field2: '测试字段2',
    field3: '测试字段3',
  },
]);
// 序号 slot名称唯一 tableIndex。 width: 设置宽度。align: 对齐方式。showTooltip: td是否一行显示,超出tooptip
const cols = ref([
  { title: '序号', prop: '', slotName: 'tableIndex', fixed: 'left', minWidth: '50px' },
  { title: '姓名', prop: 'name', showTooltip: true, minWidth: '150px' },
  { title: '性别', prop: 'sex', width: '50px' },
  { title: '工号', prop: 'no', showTooltip: true, minWidth: '120px', fixed: { position: 'left', distance: 'auto' } },
  { title: '职级', prop: 'level' },
  { title: '司龄', prop: 'years' },
  { title: '字段1', prop: 'field1' },
  { title: '字段2', prop: 'field2' },
  { title: '右自动固定', prop: 'field3', fixed: { position: 'right', distance: 'auto' } },
  { title: '描述', prop: 'des', showTooltip: true, minWidth: '400px' },
  { title: '单位', prop: 'org', showTooltip: true, minWidth: '150px', fixed: { position: 'right', distance: 'auto' } },
  {
    title: '操作',
    prop: '',
    slotName: 'handle',
    align: 'center',
    fixed: 'right',
  },
]);
</script>

固定行

通过 cellStyle 属性还可以实现固定行效果。

序号
姓名
性别
单位
描述
操作
0
王二麻子
某个公司
来自中国南方的温暖城市!
1
王二麻子
某个公司
来自中国南方的温暖城市!
2
王二麻子
某个公司
来自中国南方的温暖城市!
3
王二麻子
某个公司
来自中国南方的温暖城市!
4
王二麻子
某个公司
来自中国南方的温暖城市!
5
王二麻子
某个公司
来自中国南方的温暖城市!
6
王二麻子
某个公司
来自中国南方的温暖城市!
7
王二麻子
某个公司
来自中国南方的温暖城市!
8
王二麻子
某个公司
来自中国南方的温暖城市!
9
王二麻子
某个公司
来自中国南方的温暖城市!
10
王二麻子
某个公司
来自中国南方的温暖城市!
11
王二麻子
某个公司
来自中国南方的温暖城市!
12
王二麻子
某个公司
来自中国南方的温暖城市!
13
王二麻子
某个公司
来自中国南方的温暖城市!
14
王二麻子
某个公司
来自中国南方的温暖城市!
15
王二麻子
某个公司
来自中国南方的温暖城市!
16
王二麻子
某个公司
来自中国南方的温暖城市!
17
王二麻子
某个公司
来自中国南方的温暖城市!
18
王二麻子
某个公司
来自中国南方的温暖城市!
19
王二麻子
某个公司
来自中国南方的温暖城市!
20
王二麻子
某个公司
来自中国南方的温暖城市!
21
王二麻子
某个公司
来自中国南方的温暖城市!
示例代码
vue
<template>
  <div class="table-scroll" style="height: 200px">
    <epp-simple-table :cols="cols" :data="tableData" border="border-x" fixed-header :cell-style="cellStyle">
      <template #tableIndex="{ rowIndex }">
        <span>{{ rowIndex }}</span>
      </template>
      <template #handle>
        <el-button link type="primary">修改</el-button>
      </template>
    </epp-simple-table>
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue';

let idx = 0;
const row = {
  name: '王二麻子',
  sex: '男',
  org: '某个公司',
  des: '来自中国南方的温暖城市!',
};
const tableData = ref(new Array(22).fill(0).map((_) => Object.assign(JSON.parse(JSON.stringify(row)), { id: idx++ })));
const cols = ref([
  { title: '序号', prop: '', slotName: 'tableIndex' },
  { title: '姓名', prop: 'name', showTooltip: true, width: '100px' },
  { title: '性别', prop: 'sex', width: '50px' },
  { title: '单位', prop: 'org', showTooltip: true, width: '150px' },
  { title: '描述', prop: 'des', showTooltip: true, width: '400px' },
  { title: '操作', prop: '', slotName: 'handle', align: 'center' },
]);

// 固定5倍数的行
const cellStyle = ({ rowIndex }: { rowIndex: number }) => {
  return rowIndex % 5 === 0
    ? {
        backgroundColor: 'var(--el-fill-color-darker)',
        zIndex: 10,
        position: 'sticky',
        top: `48px`, // 48为表格头的高度
      }
    : {};
};
</script>

固定头和列

表头和列可以同时设置固定。

#
姓名
性别
手机号
住址
操作
1
费文轩
14933867329
安徽省六安市东港镇港下锡港东路8栋1204室
2
刘林
11381484641
内蒙锡林浩特市北六门村南河街8栋1204室
3
金玥傲
15000688905
黑龙江省北安市三岔路浦沅宿舍131号
4
王武
18102220035
湖北省洪湖市东五条路林机小区948号
5
卞嘉怡
11022218210
山东省招远市并州北路2条8号
6
和文杰
12548097666
陕西省安康市金国里506号517房
7
潘瑞堂
12065726257
安徽省天长市金霞街道国际商业中心121号
8
关爽
15570593023
四川省简阳市前进路506号517房
示例代码
vue
<template>
  <el-scrollbar height="200px">
    <epp-simple-table :cols="cols" :data="tableData" border="border-x" fixed-header>
      <template #tableIndex="{ rowIndex }">
        <span>{{ rowIndex + 1 }}</span>
      </template>
      <template #handle>
        <el-button link type="primary">修改</el-button>
      </template>
    </epp-simple-table>
  </el-scrollbar>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const tableData = ref([
  { id: 1, name: '费文轩', sex: '男', org: '14933867329', des: '安徽省六安市东港镇港下锡港东路8栋1204室' },
  { id: 2, name: '刘林', sex: '男', org: '11381484641', des: '内蒙锡林浩特市北六门村南河街8栋1204室' },
  { id: 3, name: '金玥傲', sex: '男', org: '15000688905', des: '黑龙江省北安市三岔路浦沅宿舍131号' },
  { id: 4, name: '王武', sex: '男', org: '18102220035', des: '湖北省洪湖市东五条路林机小区948号' },
  { id: 5, name: '卞嘉怡', sex: '女', org: '11022218210', des: '山东省招远市并州北路2条8号' },
  { id: 6, name: '和文杰', sex: '男', org: '12548097666', des: '陕西省安康市金国里506号517房' },
  { id: 7, name: '潘瑞堂', sex: '男', org: '12065726257', des: '安徽省天长市金霞街道国际商业中心121号' },
  { id: 8, name: '关爽', sex: '女', org: '15570593023', des: '四川省简阳市前进路506号517房' },
]);
// 序号 slot名称唯一 tableIndex。 width: 设置宽度。align: 对齐方式。showTooltip: td是否一行显示,超出tooptip
const cols = ref([
  { title: '#', prop: '', slotName: 'tableIndex', minWidth: '4em' },
  { title: '姓名', prop: 'name', minWidth: '7em', fixed: 'left' },
  { title: '性别', prop: 'sex', minWidth: '6em' },
  { title: '手机号', prop: 'org', minWidth: '10em' },
  { title: '住址', prop: 'des', minWidth: '26em' },
  {
    title: '操作',
    prop: '',
    slotName: 'handle',
    align: 'center',
    fixed: 'right',
  },
]);
</script>

下拉加载更多

配合 Scrollbar 组件可实现下拉加载更多。

#
用户名
性别
单位
简介
操作
1
王二麻子
某个公司
来自中国南方的温暖城市!
2
李四
某个公司
来自中国
3
张三
某个公司
来自中国北方的寒冷的城市!
4
张三2
某个公司
来自中国北方的寒冷的城市!
Loading
示例代码
vue
<template>
  <div ref="divWrapper" style="height: 200px; overflow-y: scroll">
    <epp-simple-table :cols="cols" :data="tableData" border="border-x" fixed-header>
      <template #tableIndex="{ rowIndex }">
        <span>{{ rowIndex + 1 }}</span>
      </template>
      <template #handle>
        <el-button link type="primary">修改</el-button>
      </template>
      <template v-if="hadMoreData" #more>
        <template v-if="loading">
          <el-space size="large">
            <epp-spinner size="16px" />
            <span>正在加载...</span>
          </el-space>
        </template>
      </template>
    </epp-simple-table>
  </div>
</template>
<script setup lang="ts">
import { computed, ref, toRefs, watch } from 'vue';
import { useScroll } from '@vueuse/core';

const divWrapper = ref();

let count = 1;
function id() {
  return count++;
}
const data = [
  {
    id: id(),
    name: '王二麻子',
    sex: '男',
    org: '某个公司',
    des: '来自中国南方的温暖城市!',
  },
  { id: id(), name: '李四', sex: '男', org: '某个公司', des: '来自中国' },
  {
    id: id(),
    name: '张三',
    sex: '男',
    org: '某个公司',
    des: '来自中国北方的寒冷的城市!',
  },
  {
    id: id(),
    name: '张三2',
    sex: '男',
    org: '某个公司',
    des: '来自中国北方的寒冷的城市!',
  },
];

const loading = ref(false);
const tableData = ref(JSON.parse(JSON.stringify(data)));
const cols = ref([
  { title: '#', slotName: 'tableIndex', width: '8%' },
  { title: '用户名', prop: 'name', width: '15%' },
  { title: '性别', prop: 'sex', width: '8%' },
  { title: '单位', prop: 'org', width: '20%' },
  { title: '简介', prop: 'des' },
  { title: '操作', slotName: 'handle', align: 'center', width: '10%' },
]);

const hadMoreData = computed(() => tableData.value.length < 12);
const loadMore = () => {
  if (loading.value || !hadMoreData.value) return;
  loading.value = true;
  window.setTimeout(() => {
    const moreData = JSON.parse(JSON.stringify(data));
    moreData.forEach((d: any) => {
      d.id = id();
      d.name = d.name + d.id;
    });
    tableData.value.push(...moreData);
    loading.value = false;
  }, 300);
};

const { arrivedState } = useScroll(divWrapper, { behavior: 'smooth' });
const { bottom } = toRefs(arrivedState);
watch(bottom, () => {
  if (bottom.value) {
    loadMore();
  }
});
</script>

移除表头

show-header 属性可以移除表头,让其展示为一个纯列表样式。

1
王二麻子
某个公司
来自中国南方的温暖城市!
2
李四
某个公司
来自中国
3
张三
某个公司
来自中国北方的寒冷的城市!
示例代码
vue
<template>
  <epp-simple-table :cols="cols" :data="tableData" hover :show-header="false">
    <template #tableIndex="{ rowIndex }">
      <span>{{ rowIndex + 1 }}</span>
    </template>
    <template #handle>
      <el-button link type="primary">修改</el-button>
    </template>
  </epp-simple-table>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const tableData = ref([
  {
    id: 1,
    name: '王二麻子',
    sex: '男',
    org: '某个公司',
    des: '来自中国南方的温暖城市!',
  },
  { id: 2, name: '李四', sex: '男', org: '某个公司', des: '来自中国' },
  {
    id: 3,
    name: '张三',
    sex: '男',
    org: '某个公司',
    des: '来自中国北方的寒冷的城市!',
  },
]);
const cols = ref([
  { title: '#', slotName: 'tableIndex' },
  { title: '用户名', prop: 'name' },
  { title: '性别', prop: 'sex' },
  { title: '单位', prop: 'org' },
  { title: '简介', prop: 'des' },
  { title: '操作', slotName: 'handle', align: 'center' },
]);
</script>

排序

可以通过连续点击相同的排序图标恢复默认排序。如果想自定义列头,但仍然使用默认排序图标,在非setup语法下从 SimpleTable 组件中解构出 SortableIcon 组件;setup语法请参考如下源码。

自定义列
用户名
性别
单位
简介
1
范xxxx
某个公司
来自安全应急UED的设计师来自安全应急UED的设计
2
xxx
某个公司
经验丰富的前端工程师
3
王ssss
某个公司
90后交互设计师
列中可以设置sortable属性,值为:true / false / 'descending' / 'ascending' ,并通过监听sort-change事件处理数据排序
vue
<template>
  <epp-simple-table :cols="cols" :data="tableData" @sort-change="sortChange">
    <template #index>
      自定义列
      <EppSimpleTable.SortableIcon sortable @sort-change="(val) => sortChange('id', val)" />
    </template>
  </epp-simple-table>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { EppSimpleTable } from 'element-plus-plus';

const defaultData = [
  {
    id: 1,
    name: '范xxxx',
    sex: '女',
    org: '某个公司',
    des: '来自安全应急UED的设计师来自安全应急UED的设计',
  },
  {
    id: 2,
    name: 'xxx',
    sex: '男',
    org: '某个公司',
    des: '经验丰富的前端工程师',
  },
  {
    id: 3,
    name: '王ssss',
    sex: '男',
    org: '某个公司',
    des: '90后交互设计师',
  },
];
const tableData = ref(JSON.parse(JSON.stringify(defaultData)));
const cols = ref([
  { title: '序号', prop: 'id', headerSlotName: 'index' },
  { title: '用户名', prop: 'name', sortable: true },
  { title: '性别', prop: 'sex', sortable: false },
  { title: '单位', prop: 'org', sortable: 'descending' },
  {
    title: '简介',
    prop: 'des',
    showTooltip: true,
    width: '40%',
    tooltipProps: { width: '200px', popperClass: 'test-tip' },
    sortable: 'ascending',
  },
]);

const sortChange = (prop: string, sort: string) => {
  // 仅作为示例,实际项目需要通过调取后台API实现
  console.log('soring...', prop, sort);
  if (sort) {
    tableData.value.sort((d1: any, d2: any) => {
      const result = String(d1[prop]).localeCompare(String(d2[prop]));
      return sort === 'ascending' ? result : result * -1;
    });
  } else {
    tableData.value = JSON.parse(JSON.stringify(defaultData));
  }
};
</script>

筛选

如果想自定义列头,但仍然使用默认排序图标,在非setup语法下从 SimpleTable 组件中解构出 FilterIcon 组件;setup语法请参考如下源码。

自定义列
用户名
单位
简介
操作
1
范xx
某个公司
来自安全应急UED的设计师来自安全应急UED的设计
2
xxx
某个公司
经验丰富的前端工程师
3
王xxx
某个公司
90后交互设计师
列中可以设置 filter 对象,提供 slotName(必选)、placement(参考Popover文档)、popperClass 属性。slot中提供 close 方法用来手工关闭弹出框。
vue
<template>
  <epp-simple-table :cols="cols" :data="tableData">
    <template #filterSlot="{ close }">
      <el-space direction="vertical" size="large">
        <el-space direction="vertical" size="large">
          <el-checkbox v-mode="selectedItems" value="1">条件1</el-checkbox>
          <el-checkbox v-mode="selectedItems" value="2">条件2</el-checkbox>
          <el-checkbox v-mode="selectedItems" value="3">条件3</el-checkbox>
        </el-space>
        <el-button type="primary" size="sm" class="m-t-md" @click="close">确定</el-button>
      </el-space>
    </template>
    <template #index>
      自定义列
      <EppSimpleTable.FilterIcon placement="right">
        <template #default="{ close }">
          <el-space direction="vertical" size="large">
            <el-space direction="vertical" size="large">
              <el-checkbox v-mode="selectedItems" value="1">条件1</el-checkbox>
              <el-checkbox v-mode="selectedItems" value="2">条件2</el-checkbox>
              <el-checkbox v-mode="selectedItems" value="3">条件3</el-checkbox>
            </el-space>
            <el-button type="primary" size="sm" class="m-t-md" @click="close">确定</el-button>
          </el-space>
        </template>
      </EppSimpleTable.FilterIcon>
    </template>
  </epp-simple-table>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { EppSimpleTable } from 'element-plus-plus';

const tableData = ref([
  {
    id: 1,
    name: '范xx',
    sex: '女',
    org: '某个公司',
    des: '来自安全应急UED的设计师来自安全应急UED的设计',
  },
  {
    id: 2,
    name: 'xxx',
    sex: '男',
    org: '某个公司',
    des: '经验丰富的前端工程师',
  },
  {
    id: 3,
    name: '王xxx',
    sex: '男',
    org: '某个公司',
    des: '90后交互设计师',
  },
]);
const cols = ref([
  { title: '序号', prop: 'id', headerSlotName: 'index' },
  {
    title: '用户名',
    prop: 'name',
    filter: {
      slotName: 'filterSlot',
      placement: 'top',
      popperClass: 'test-filter-slot',
    },
  },
  { title: '单位', prop: 'org' },
  {
    title: '简介',
    prop: 'des',
    showTooltip: true,
    width: '40%',
    tooltipProps: { width: '200px', popperClass: 'test-tip' },
    filter: { slotName: 'filterSlot' },
  },
  { title: '操作', slotName: 'handle', align: 'center' },
]);

const selectedItems = ref<string[]>([]);
</script>

高亮行

选择单行数据时使用色块表示。

用户名
性别
单位
简介
操作
1
范xxxx
某个公司
来自安全应急UED的设计师来自安全应急UED的设计
2
xxx
某个公司
经验丰富的前端工程师
3
王ssss
某个公司
90后交互设计师

SimpleTable 组件提供了单选的支持, 只需要配置highlight-current-row属性即可实现单选。 之后由current-change事件来管理选中时触发的事件,它会传入 currentRow,oldCurrentRow。
vue
<template>
  <epp-simple-table
    ref="tableRef"
    :cols="cols"
    :data="tableData"
    highlight-current-row
    @current-change="currentChange"
    @row-click="rowClick"
  />
  <br />
  <el-button class="m-r-md" @click="setCurrent(tableData[0])">选中第一行</el-button>
  <el-button @click="setCurrent()">取消选择</el-button>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const tableRef = ref();
const tableData = ref([
  {
    id: 1,
    name: '范xxxx',
    sex: '女',
    org: '某个公司',
    des: '来自安全应急UED的设计师来自安全应急UED的设计',
  },
  {
    id: 2,
    name: 'xxx',
    sex: '男',
    org: '某个公司',
    des: '经验丰富的前端工程师',
  },
  {
    id: 3,
    name: '王ssss',
    sex: '男',
    org: '某个公司',
    des: '90后交互设计师',
  },
]);
const cols = ref([
  { title: '序号', prop: 'id', headerSlotName: 'index' },
  {
    title: '用户名',
    prop: 'name',
    sortable: true,
    filter: {
      slotName: 'filterSlot',
      placement: 'top',
      popperClass: 'test-filter-slot',
    },
  },
  { title: '性别', prop: 'sex' },
  { title: '单位', prop: 'org' },
  {
    title: '简介',
    prop: 'des',
    showTooltip: true,
    width: '40%',
    tooltipProps: { width: '200px', popperClass: 'test-tip' },
    filter: { slotName: 'filterSlot' },
  },
  { title: '操作', slotName: 'handle', align: 'center' },
]);

const currentChange = (now: Record<string, any>, old: Record<string, any>) => {
  console.log(now, old);
};
const rowClick = () => {
  console.log('row-click');
};
const setCurrent = (row?: Record<string, any>) => {
  tableRef.value.setCurrentRow(row);
};
</script>

展开行

当行内容过多并且不想显示横向滚动条时,可以使用 SimpleTable 展开行功能。可以定义多列同时展开。

#
用户名
性别
单位
简介
操作
点我展开 / 范xx
某个公司
来自安全应急UED的设计师来自安全应急UED的设计

某个公司 / 来自安全应急UED的设计师来自安全应急UED的设计

某个公司
经验丰富的前端工程师

手工展开数据

点我展开 / 王xx
某个公司
90后交互设计师
通过设置 expand 对象 和 slot 可以开启展开行功能。expand有两个属性:slotNamehideLabel,hideLabel默认为false
vue
<template>
  <epp-simple-table ref="tableRef" :cols="cols" :data="tableData" :expand-row-keys="['1index', '2nameExpand']">
    <template #index="{ row }">
      <p>{{ row.org }} / {{ row.des }}</p>
    </template>
    <template #name="{ row }"> <a href="javascript:;" @click="expand(row)">点我展开</a> / {{ row.name }} </template>
    <template #nameExpand>
      <p>手工展开数据</p>
    </template>
    <template #des="{ row }">
      <p>{{ row.sex }} / {{ row.des }}</p>
    </template>
  </epp-simple-table>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const tableRef = ref();
const tableData = ref([
  {
    id: 1,
    name: '范xx',
    sex: '女',
    org: '某个公司',
    des: '来自安全应急UED的设计师来自安全应急UED的设计',
  },
  {
    id: 2,
    name: 'xxx',
    sex: '男',
    org: '某个公司',
    des: '经验丰富的前端工程师',
  },
  {
    id: 3,
    name: '王xx',
    sex: '男',
    org: '某个公司',
    des: '90后交互设计师',
  },
]);
const cols = ref([
  { title: '#', prop: 'id', expand: { slotName: 'index', hideLabel: true } },
  { title: '用户名', prop: 'name', slotName: 'name', expand: { slotName: 'nameExpand' } },
  { title: '性别', prop: 'sex' },
  { title: '单位', prop: 'org' },
  {
    title: '简介',
    prop: 'des',
    showTooltip: true,
    width: '40%',
    expand: { slotName: 'des' },
    tooltipProps: { width: '200px', popperClass: 'test-tip' },
  },
  { title: '操作', slotName: 'handle', align: 'center' },
]);

const expand = (row: { id: number }) => {
  tableRef.value.toggleExpand(row.id, 'nameExpand');
};
</script>

树形数据与懒加载

支持树类型的数据的显示。 当 row 中包含 children 字段时,被视为树形数据。 渲染树形数据时,必须要指定 row-key。支持子节点数据异步加载。 设置 Table 的加载函数 load 。 通过指定 row 中的hasChildren字段来指定哪些行是包含子节点。 children与hasChildren都可以通过 tree-props 配置。first-column-index 属性用来设置展开行为所作用的列。

ID
用户名
性别
单位
简介
操作


ID
用户名
性别
单位
简介
操作
当children字段有数组值时,将会忽略hasChildren字段。需要异步加载数据时,一定要谨慎设置default-expand-all属性为true值
vue
<template>
  <epp-simple-table :cols="cols" :data="tableData" :load="load" :expand-row-keys="['1']">
    <template #tableIndex="{ row }">
      <span>{{ row.id }}</span>
    </template>
    <template #handle>
      <a>修改</a>
    </template>
  </epp-simple-table>
  <br /><br />
  <epp-simple-table :cols="cols" :data="tableData" :load="load" :expand-row-keys="['1']" :first-column-index="1">
    <template #tableIndex="{ row }">
      <span>{{ row.id }}</span>
    </template>
    <template #handle>
      <a>修改</a>
    </template>
  </epp-simple-table>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { isClient } from '@vueuse/core';

let count = 10000;
const tableData = ref();
const cols = ref([
  { title: 'ID', slotName: 'tableIndex' },
  { title: '用户名', prop: 'name' },
  { title: '性别', prop: 'sex' },
  { title: '单位', prop: 'org' },
  { title: '简介', prop: 'des', width: '220px', showTooltip: true },
  { title: '操作', slotName: 'handle', align: 'center' },
]);

const load = (_: Record<string, any>, __: Record<string, any>, resolve: (data: Record<string, any>[]) => void) => {
  window.setTimeout(() => {
    resolve([
      {
        id: count++,
        name: '王二麻子',
        sex: '男',
        org: '某个公司',
        des: '来自中国南方的温暖城市哦!',
        hasChildren: true,
      },
      {
        id: count++,
        name: '王二麻子',
        sex: '男',
        org: '某个公司',
        des: '来自中国南方的温暖城市!',
        children: [
          {
            id: count++,
            name: '王二麻子',
            sex: '男',
            org: '某个公司',
            des: '来自中国南方的温暖城市!',
          },
        ],
      },
    ]);
  }, 3000);
};

if (isClient) {
  window.setTimeout(() => {
    tableData.value = [
      {
        id: 1,
        name: '王二麻子',
        sex: '男',
        org: '某个公司',
        des: '来自中国南方的温暖城市啊!',
        children: [
          {
            id: 11,
            name: '王二麻子11',
            sex: '男',
            org: '某个公司',
            des: '来自中国南方的温暖城市!',
            children: [
              {
                id: 111,
                name: '王二麻子111',
                sex: '男',
                org: '某个公司',
                des: '来自中国南方的温暖城市!',
              },
              {
                id: 112,
                name: '王二麻子112',
                sex: '男',
                org: '某个公司',
                des: '来自中国南方的温暖城市!',
              },
            ],
          },
          {
            id: 12,
            name: '王二麻子12',
            sex: '男',
            org: '某个公司',
            des: '来自中国南方的温暖城市!',
            children: [],
          },
        ],
      },
      {
        id: 2,
        name: '李四',
        sex: '男',
        org: '某个公司',
        des: '来自中国',
        hasChildren: true,
      },
      {
        id: 3,
        name: '张三',
        sex: '男',
        org: '某个公司',
        des: '来自中国北方的寒冷的城市!',
      },
    ];
  }, 100);
}
</script>

合并行或列

多行或多列共用一个数据时,可以合并行或列。

id
用户名
Amount1
Amount2
Amount3
12987122
234
3.2
10
12987123
Tom
165
4.43
12
12987124
324
1.9
9
12987125
Tom
621
2.2
17
12987126
539
4.1
15
id
用户名
Amount1
Amount2
Amount3
12987122
Tom
234
3.2
10
Tom
165
4.43
12
12987124
Tom
324
1.9
9
Tom
621
2.2
17
12987126
Tom
539
4.1
15
通过给 table 传入span-method方法可以实现合并行或列, 方法的参数是一个对象,里面包含当前行 row、当前列 column、当前行号 rowIndex、当前列号 columnIndex 四个属性。 该函数可以返回一个包含两个元素的数组,第一个元素代表 rowspan,第二个元素代表 colspan。 也可以返回一个键名为 rowspan 和 colspan 的对象。
vue
<template>
  <epp-simple-table :cols="cols" :data="tableData" border="bordered" :span-method="arraySpanMethod" />
  <epp-simple-table :cols="cols" :data="tableData" border="bordered" class="m-t-md" :span-method="objectSpanMethod" />
</template>
<script setup lang="ts">
import { ref } from 'vue';

const tableData = ref([
  {
    id: '12987122',
    name: 'Tom',
    amount1: '234',
    amount2: '3.2',
    amount3: 10,
  },
  {
    id: '12987123',
    name: 'Tom',
    amount1: '165',
    amount2: '4.43',
    amount3: 12,
  },
  {
    id: '12987124',
    name: 'Tom',
    amount1: '324',
    amount2: '1.9',
    amount3: 9,
  },
  {
    id: '12987125',
    name: 'Tom',
    amount1: '621',
    amount2: '2.2',
    amount3: 17,
  },
  {
    id: '12987126',
    name: 'Tom',
    amount1: '539',
    amount2: '4.1',
    amount3: 15,
  },
]);
const cols = ref([
  { title: 'id', prop: 'id' },
  { title: '用户名', prop: 'name' },
  { title: 'Amount1', prop: 'amount1' },
  { title: 'Amount2', prop: 'amount2' },
  { title: 'Amount3', prop: 'amount3' },
]);

const arraySpanMethod = ({ rowIndex, columnIndex }: { rowIndex: number; columnIndex: number }) => {
  if (rowIndex % 2 === 0) {
    if (columnIndex === 0) {
      return [1, 2];
    } else if (columnIndex === 1) {
      return [0, 0];
    }
  }
};

const objectSpanMethod = ({ rowIndex, columnIndex }: { rowIndex: number; columnIndex: number }) => {
  if (columnIndex === 0) {
    if (rowIndex % 2 === 0) {
      return {
        rowspan: 2,
        colspan: 1,
      };
    } else {
      return {
        rowspan: 0,
        colspan: 0,
      };
    }
  }
};
</script>

多级表头

数据结构比较复杂的时候,可使用多级表头来展现数据的层次关系。

日期
配送信息
姓名
地址信息
省/市
城市
地址
操作
2016-05-03
Tom
California
Los Angeles
No. 189, Grove St, Los Angeles
2016-05-02
Tom
California
Los Angeles
No. 189, Grove St, Los Angeles
2016-05-04
Tom
California
Los Angeles
No. 189, Grove St, Los Angeles
2016-05-01
Tom
California
Los Angeles
No. 189, Grove St, Los Angeles
2016-05-08
Tom
California
Los Angeles
No. 189, Grove St, Los Angeles
2016-05-06
Tom
California
Los Angeles
No. 189, Grove St, Los Angeles
2016-05-07
Tom
California
Los Angeles
No. 189, Grove St, Los Angeles
通过colschildren 属性嵌套实现多级表头
vue
<template>
  <epp-simple-table :cols="cols" :data="tableData" border="bordered">
    <template #handle>
      <a>修改</a>
    </template>
  </epp-simple-table>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const tableData = ref([
  {
    date: '2016-05-03',
    name: 'Tom',
    state: 'California',
    city: 'Los Angeles',
    address: 'No. 189, Grove St, Los Angeles',
    zip: 'CA 90036',
  },
  {
    date: '2016-05-02',
    name: 'Tom',
    state: 'California',
    city: 'Los Angeles',
    address: 'No. 189, Grove St, Los Angeles',
    zip: 'CA 90036',
  },
  {
    date: '2016-05-04',
    name: 'Tom',
    state: 'California',
    city: 'Los Angeles',
    address: 'No. 189, Grove St, Los Angeles',
    zip: 'CA 90036',
  },
  {
    date: '2016-05-01',
    name: 'Tom',
    state: 'California',
    city: 'Los Angeles',
    address: 'No. 189, Grove St, Los Angeles',
    zip: 'CA 90036',
  },
  {
    date: '2016-05-08',
    name: 'Tom',
    state: 'California',
    city: 'Los Angeles',
    address: 'No. 189, Grove St, Los Angeles',
    zip: 'CA 90036',
  },
  {
    date: '2016-05-06',
    name: 'Tom',
    state: 'California',
    city: 'Los Angeles',
    address: 'No. 189, Grove St, Los Angeles',
    zip: 'CA 90036',
  },
  {
    date: '2016-05-07',
    name: 'Tom',
    state: 'California',
    city: 'Los Angeles',
    address: 'No. 189, Grove St, Los Angeles',
    zip: 'CA 90036',
  },
]);
const cols = ref([
  { title: '日期', prop: 'date' },
  {
    title: '配送信息',
    prop: 'delivery',
    children: [
      { title: '姓名', prop: 'name' },
      {
        title: '地址信息',
        prop: 'address',
        children: [
          { title: '省/市', prop: 'state' },
          { title: '城市', prop: 'city' },
          { title: '地址', prop: 'address' },
          { title: '操作', prop: 'zip', slotName: 'handle' },
        ],
      },
    ],
  },
]);
</script>

表尾合计行

若表格展示的是各类数字,可以在表尾显示各列的合计。

id
用户名
Amount1
Amount2
Amount3
12987122
Tom
234
3.2
10
12987123
Tom
165
4.43
12
12987124
Tom
324
1.9
9
12987125
Tom
621
2.2
17
12987126
Tom
539
4.1
15
合计¥3232¥1212.22¥90.22
可以通过自定义 foot slot实现
vue
<template>
  <epp-simple-table :cols="cols" :data="tableData" border="bordered">
    <template #foot>
      <tr>
        <td colspan="2"><strong>合计</strong></td>
        <td>¥3232</td>
        <td>¥1212.22</td>
        <td>¥90.22</td>
      </tr>
    </template>
  </epp-simple-table>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const tableData = ref([
  {
    id: '12987122',
    name: 'Tom',
    amount1: '234',
    amount2: '3.2',
    amount3: 10,
  },
  {
    id: '12987123',
    name: 'Tom',
    amount1: '165',
    amount2: '4.43',
    amount3: 12,
  },
  {
    id: '12987124',
    name: 'Tom',
    amount1: '324',
    amount2: '1.9',
    amount3: 9,
  },
  {
    id: '12987125',
    name: 'Tom',
    amount1: '621',
    amount2: '2.2',
    amount3: 17,
  },
  {
    id: '12987126',
    name: 'Tom',
    amount1: '539',
    amount2: '4.1',
    amount3: 15,
  },
]);
const cols = ref([
  { title: 'id', prop: 'id' },
  { title: '用户名', prop: 'name' },
  { title: 'Amount1', prop: 'amount1' },
  { title: 'Amount2', prop: 'amount2' },
  { title: 'Amount3', prop: 'amount3' },
]);
</script>

隐藏列

toggleColumn 方法支持对列的隐藏或者显示操作。

#
用户名
性别
单位
简介
操作
1
范xxx
某个公司
来自安全应急UED的设计师来自安全应急
2
xxx
某个公司
经验丰富的前端工程师
3
王xxxxx
某个公司
90后交互设计师


暂不支持对多级表头以及存在合并单元格的表格进行操作
vue
<template>
  <epp-simple-table ref="simpleTableRef" :cols="cols" :data="tableData">
    <template #handle>
      <a>修改</a>
    </template>
  </epp-simple-table>
  <br /><br />
  <el-button type="primary" @click="toggleColumn">隐藏/显示第3列</el-button>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const simpleTableRef = ref();
const tableData = ref([
  {
    id: 1,
    name: '范xxx',
    sex: '女',
    org: '某个公司',
    des: '来自安全应急UED的设计师来自安全应急',
  },
  {
    id: 2,
    name: 'xxx',
    sex: '男',
    org: '某个公司',
    des: '经验丰富的前端工程师',
  },
  {
    id: 3,
    name: '王xxxxx',
    sex: '男',
    org: '某个公司',
    des: '90后交互设计师',
  },
]);
const cols = ref([
  { title: '#', prop: 'id' },
  { title: '用户名', prop: 'name' },
  { title: '性别', prop: 'sex' },
  { title: '单位', prop: 'org', align: 'center' },
  {
    title: '简介',
    prop: 'des',
    showTooltip: true,
    width: '40%',
    tooltipProps: { width: '200px', popperClass: 'test-tip' },
  },
  { title: '操作', slotName: 'handle', align: 'center' },
]);

const toggleColumn = () => {
  simpleTableRef.value.toggleColumn(2);
};
</script>

拖拽排序

利用Sortablejs实现表格行拖拽移动位置。

用户名
年龄
单位
简介
操作
柏庐
20
某个公司
来自UED的设计师来自UED的设计来自UED的设计师来自UED的设计来自UED的设计师来自UED的设计来自UED的设计师来自UED的设计来自UED的设计师来自UED的设计来自UED的设计师来自UED的设计
军结
22
某个公司
经验丰富的前端工程师
钞洋
28
某个公司
90后交互设计师
钞洋1
28
某个公司
90后交互设计师
钞洋2
28
某个公司
90后交互设计师
示例代码
vue
<template>
  <epp-simple-table
    :cols="cols"
    :data="tableData"
    class="sortable-table"
    @row-click="rowClicked"
    @cell-click="cellClicked"
  >
    <template #firstCol>
      <el-checkbox v-model="selectedAll" :indeterminate="isIndeterminate" @change="selectAll" />
    </template>
    <template #tableIndex="{ row }">
      <el-checkbox v-model="selectedRows" :value="row.id" @change="selectRow(row.id)">{{ '' }}</el-checkbox>
    </template>

    <template #handle>
      <a>修改</a>
    </template>
  </epp-simple-table>
</template>
<script setup lang="ts">
import { ref, onMounted, nextTick } from 'vue';
import { isClient } from '@vueuse/core';
import Sortable from 'sortablejs';
import type { ColumnType } from 'element-plus-plus';

const selectedAll = ref(false);
const selectedRows = ref<number[]>([]);
const isIndeterminate = ref(false);

const tableData = ref([
  {
    id: 1,
    name: '柏庐',
    sex: '女',
    org: '某个公司',
    des: '来自UED的设计师来自UED的设计来自UED的设计师来自UED的设计来自UED的设计师来自UED的设计来自UED的设计师来自UED的设计来自UED的设计师来自UED的设计来自UED的设计师来自UED的设计',
    otherInfo: {
      age: 20,
    },
  },
  {
    id: 2,
    name: '军结',
    sex: '男',
    org: '某个公司',
    des: '经验丰富的前端工程师',
    otherInfo: {
      age: 22,
    },
  },
  {
    id: 3,
    name: '钞洋',
    sex: '男',
    org: '某个公司',
    des: '90后交互设计师',
    otherInfo: {
      age: 28,
    },
  },
  {
    id: 4,
    name: '钞洋1',
    sex: '男',
    org: '某个公司',
    des: '90后交互设计师',
    otherInfo: {
      age: 28,
    },
  },
  {
    id: 5,
    name: '钞洋2',
    sex: '男',
    org: '某个公司',
    des: '90后交互设计师',
    otherInfo: {
      age: 28,
    },
  },
]);
const cols = ref([
  { title: '#', slotName: 'tableIndex', headerSlotName: 'firstCol', width: '3em' },
  { title: '用户名', prop: 'name' },
  { title: '年龄', prop: 'otherInfo.age' },
  { title: '单位', prop: 'org', align: 'center' },
  {
    title: '简介',
    prop: 'des',
    align: 'center',
    showTooltip: true,
    width: '40%',
    tooltipProps: { width: '200px', popperClass: 'test-tip' },
  },
  { title: '操作', slotName: 'handle', align: 'center' },
]);

const selectAll = () => {
  if (selectedAll.value) {
    selectedRows.value.splice(0, selectedRows.value.length);
    selectedRows.value.push(...tableData.value.map((d) => d.id));
    isIndeterminate.value = false;
  } else {
    selectedRows.value.splice(0, selectedRows.value.length);
  }
};
const selectRow = () => {
  selectedAll.value = selectedRows.value.length === tableData.value.length;
  if (selectedRows.value.length > 0 && selectedAll.value == false) {
    isIndeterminate.value = true;
  } else {
    isIndeterminate.value = false;
  }
};
const rowClicked = (row: Record<string, any>, rowIndex: number, event: Event) => {
  console.log('rowClicked', row, rowIndex, event);
};
const cellClicked = (row: Record<string, any>, col: ColumnType, rowIndex: number, colIndex: number, event: Event) => {
  console.log('cellClicked', row, col, rowIndex, colIndex, event);
};

onMounted(() => {
  if (!isClient) return;
  const el = document.querySelector('.sortable-table > tbody');
  Sortable.create(el, {
    disabled: false,
    handle: 'tr',
    animation: 150,
    onEnd: (e: any) => {
      const arr = tableData.value;
      arr.splice(e.newIndex, 0, arr.splice(e.oldIndex, 1)[0]);
      nextTick(() => {
        tableData.value = arr;
      });
    },
  });
});
</script>

空数据

序号
姓名
性别
操作
No Data
示例代码
vue
<template>
  <epp-simple-table :cols="cols" border="border-x" :data="tableData" />
</template>
<script setup lang="ts">
import { ref } from 'vue';

const tableData = ref([]);
// 序号 slot名称唯一 tableIndex。 width: 设置宽度。align: 对齐方式。showTooltip: td是否一行显示,超出tooptip
const cols = ref([
  { title: '序号', prop: '', slotName: 'tableIndex' },
  { title: '姓名', prop: 'name' },
  { title: '性别', prop: 'sex' },
  { title: '操作', prop: '', align: 'center' },
]);
</script>

未知数据

序号
姓名
性别
操作

可能数据报错了哦~

在传递的数据为 null 或者 undefined 时,可以自定义 unknown slot
vue
<template>
  <epp-simple-table :cols="cols" border="border-x" :data="tableData">
    <template #unknown>
      <p style="text-align: center">可能数据报错了哦~</p>
    </template>
  </epp-simple-table>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const tableData = ref(null);
// 序号 slot名称唯一 tableIndex。 width: 设置宽度。align: 对齐方式。showTooltip: td是否一行显示,超出tooptip
const cols = ref([
  { title: '序号', prop: '', slotName: 'tableIndex' },
  { title: '姓名', prop: 'name' },
  { title: '性别', prop: 'sex' },
  { title: '操作', prop: '', align: 'center' },
]);
</script>

Attributes

参数说明类型可选值默认值
row-key行数据的 Key,用来优化 SimpleTable 的渲染。如果表格数据标识符不是id字段,请一定要设置此值string / function(row): string-id
border为表格设置边框样式stringborderless/bordered/border-x/border-y
padding设置表格两端的 padding 尺寸string通用尺寸标签/自定义尺寸
cell-padding设置Td的 padding 尺寸string通用尺寸标签/自定义尺寸
gaplist模式下,设置表格行间距stringcss尺寸
gap-xlist模式下,设置表格行横向间距stringcss尺寸
gap-ylist模式下,设置表格行纵向间距stringcss尺寸
hover表格行悬停效果boolean
cross-hover表格列悬停效果boolean
stripe表格条纹效果boolean / stringtrue / false / odd / evenfalse
list列表样式booleanfalse
auto-height使Th和Td的高度变为autobooleanfalse
fixed-header固定表头boolean-
fixed-footer固定表尾boolean-
show-header是否显示表头boolean-true
size表格大小stringsm / md / lg-
resize是否可以拖拽表头改变列宽boolean-false
scroll-container设置固定列时,如果滚动容器不是表格的直接父元素或者Scrollbar组件,需要设置此属性,用以支持滚动时固定列阴影效果string / HTMLElement--
highlight-current-row是否要高亮当前行boolean-false
expand-row-keys默认展开,同时适用行展开与树展开。行展开时用行rowKey+slotName作为唯一标识符;树展开时使用rowKey作为唯一标识符。数组值一定是字符串。array--
default-expand-all是否默认展开所有行,当 SimpleTable 包含展开行存在或者为树形表格时有效boolean-false
row-class-name行的 className 的回调方法,也可以使用字符串为所有行设置一个固定的 className。function({ row, rowIndex }) / string--
row-style行的 style 的回调方法,也可以使用一个固定的 Object 为所有行设置一样的 Style。function({ row, rowIndex }) / object--
cell-class-name单元格的 className 的回调方法,也可以使用字符串为所有单元格设置一个固定的 className。function({ row, column, rowIndex, columnIndex }) / string--
cell-style单元格的 style 的回调方法,也可以使用一个固定的 Object 为所有单元格设置一样的 Style。function({ row, column, rowIndex, columnIndex }) / object--
header-row-class-name表头行的 className 的回调方法,也可以使用字符串为所有表头行设置一个固定的 className。function({ row, rowIndex }) / string--
header-row-style表头行的 style 的回调方法,也可以使用一个固定的 Object 为所有表头行设置一样的 Style。function({ row, rowIndex }) / object--
header-cell-class-name表头单元格的 className 的回调方法,也可以使用字符串为所有表头单元格设置一个固定的 className。function({ row, column, rowIndex, columnIndex }) / string--
header-cell-style表头单元格的 style 的回调方法,也可以使用一个固定的 Object 为所有表头单元格设置一样的 Style。function({ row, column, rowIndex, columnIndex }) / object--
span-method合并行或列的计算方法function({ row, column, rowIndex, columnIndex })--
first-column-index树形展开操作作用的列number-0
tree-props渲染嵌套数据的配置选项object-{ hasChildren: 'hasChildren', children: 'children' }
load加载子节点数据的函数,函数第二个参数包含了节点的层级信息function(row, treeNode, resolve)--
cols列配置,参见下表array--

cols

参数说明类型可选值默认值
columnKey列key,如果动态切换表格列,需要设置此值。否则列宽会计算错误string
title表格标题string
prop表格列属性名称string
showTooltip是否显示 tooltip,需要配合列 width 值使用booleanfalse
tooltipPropstooltip 属性,参考 Popover 组件object
align水平对齐方式stringleft/center/rightleft
width列宽string-
minWidth最小列宽string-
maxWidth最大列宽string-
fixed固定列string / objectleft / right / { position: string; distance: string; }-
headerSlotName列头 slot 名称,默认参数为 col,请参考示例string--
sortable是否为排序列boolean / stringtrue / false / 'ascending' / 'descending'-
filter列筛选设置object{ slotName: string, placement: string, popperClass: string }--
expand展开列设置object{ slotName: string, hideLabel: boolean }--
children子列信息array--
formatter用来格式化内容function(row, column, cellValue, rowIndex, columnIndex)--

Events

事件名称说明回调参数
row-click行单击事件row, rowIndex, event
cell-click单元格单击事件row, col, rowIndex, colIndex, event
sort-change排序事件prop, sort
current-change当表格的当前行发生变化的时候会触发该事件,如果要高亮当前行,请打开表格的 highlight-current-row 属性currentRow, oldCurrentRow
expand展开事件expanded, rowkey, slotName
tree-expand树展开事件expanded, row

Methods

方法名说明参数
toggleExpand展开/折叠行。由于每行可能有多个展开,所以需要传递需要展开的slotNamerowKey, slotName
toggleExpandTree展开树row
toggleColumn显示/隐藏列index, show(show可选)
setCurrentRow用于单选表格,设定某一行为选中行, 如果调用时不加参数,则会取消目前高亮行的选中状态row
clearTooltip隐藏tooltip-

Slots

名称说明
empty无数据时的提示
unknown表格数据为null或者undefined时,自定义内容
more下拉加载时,自定义内容
foot表尾