Skip to content

Table Component ​

Table is a high-performance table component developed with Uniapp. It supports fixed columns, sorting, striped rows, custom slots, and other features, making it suitable for a wide range of data display scenarios.

📌 Platform Differences ​

APP(vue)H5WeChat Mini ProgramAlipay Mini Program
✔✔✔✔

⚠️ Notes ​

Notes

  1. It is recommended to use numbers for the table height (height) and row height (rowHeight); the component will automatically append the px unit
  2. Fixed columns must specify the width property, otherwise layout issues may occur
  3. For large datasets (>1000 rows), it is recommended to use virtual scrolling or paginated loading to improve performance
  4. The formatter function should be kept as simple as possible to avoid complex calculations affecting rendering performance
  5. For long text in table content, it is recommended to enable the ellipsis property to avoid layout breakage

Main Features ​

  • Support for left and right fixed columns
  • Header sorting functionality
  • Striped row style
  • Custom row height and table height
  • Empty state and loading state display
  • Rich slot support
  • Responsive design

🏯 Basic Usage Example ​

vue
<template>
    <hy-table :data="tableData" :columns="columns" :height="500" stripe></hy-table>
</template>
ts
import { ref } from 'vue';

// Table data
const tableData = ref([
    { id: 1, name: '张三', age: 28, gender: '男', address: '北京市朝阳区' },
    { id: 2, name: '李四', age: 32, gender: '女', address: '上海市浦东新区' },
    { id: 3, name: '王五', age: 25, gender: '男', address: '广州市天河区' },
    // More data...
]);

// Column configuration
const columns = ref([
    { title: 'ID', key: 'id', width: 80, fixed: 'left' },
    { title: '姓名', key: 'name', width: 120 },
    { title: '年龄', key: 'age', width: 100, sortable: true },
    { title: '性别', key: 'gender', width: 100 },
    { title: '地址', key: 'address', width: 300, ellipsis: true },
    { title: '操作', key: 'action', width: 150, fixed: 'right' },
]);

Fixed Columns / Slots ​

Note

Because dynamic slots cannot be used in WeChat Mini Programs, this slot approach is implemented, passing all content through slots

html
<hy-table :data="tableData" :columns="columns" :height="500">
    <!-- Custom action column -->
    <template #right="{ row, col, index }">
        <hy-flex v-if="col.key === 'action'" gap="2">
            <hy-button text="编辑" size="mini" plain :border="false"></hy-button>
            <hy-button type="error" size="mini" text="删除" plain :border="false"></hy-button>
        </hy-flex>
        <text v-else>{{ row[col.key] }}</text>
    </template>
</hy-table>
ts
import { reactive } from 'vue';

const columns2 = reactive([
    { title: 'ID', key: 'id', width: 40, fixed: 'left', align: 'center' },
    { title: '姓名', key: 'name', width: 80, fixed: 'left' },
    { title: '性别', key: 'sex', width: 80 },
    { title: '年龄', key: 'age', width: 80, sortable: true },
    { title: '邮箱', key: 'email', width: 200, ellipsis: true },
    { title: '地址', key: 'address', width: 300, ellipsis: true },
    { title: '电话', key: 'phone', width: 150, ellipsis: true },
    { title: '公司', key: 'company', width: 150, ellipsis: true },
    { title: '职位', key: 'position', width: 150, ellipsis: true },
    { title: '操作', key: 'action', width: 100, fixed: 'right' },
]);

const tableData = reactive([
    {
        id: 1,
        name: '张三',
        age: 12,
        sex: '男',
        address: '安徽省合肥市肥西县',
        status: 1,
        email: 'zhangsan@example.com',
        phone: '13800138001',
        company: '科技有限公司',
        position: '前端开发',
    },
    {
        id: 2,
        name: '李四',
        age: 18,
        sex: '男',
        address: '安徽省合肥市肥西县',
        status: 1,
        email: 'lisi@example.com',
        phone: '13800138002',
        company: '互联网公司',
        position: '后端开发',
    },
    {
        id: 3,
        name: '王二',
        age: 28,
        sex: '男',
        address: '安徽省合肥市肥西县',
        status: 1,
        email: 'wangwu@example.com',
        phone: '13800138003',
        company: '金融科技',
        position: '产品经理',
    },
    {
        id: 4,
        name: '麻子',
        age: 17,
        sex: '男',
        address: '内蒙古自治区呼伦贝尔市莫力达瓦达幹尔自治旗',
        status: 0,
        email: 'mazi@example.com',
        phone: '13800138004',
        company: '电子商务',
        position: '设计师',
    },
    {
        id: 5,
        name: '丧彪',
        age: 80,
        sex: '男',
        address: '地府',
        status: 0,
        email: 'sangbiao@example.com',
        phone: '13800138005',
        company: '冥界科技',
        position: 'CEO',
    },
    {
        id: 6,
        name: '奥德彪',
        age: 23,
        sex: '男',
        address: '非洲',
        status: 0,
        email: 'aodebiao@example.com',
        phone: '13800138006',
        company: '国际贸易',
        position: '销售经理',
    },
    {
        id: 7,
        name: '宙斯',
        age: 33,
        sex: '男',
        address: '宇宙太阳系',
        status: 0,
        email: 'zeus@example.com',
        phone: '13800138007',
        company: '奥林匹斯集团',
        position: '众神之王',
    },
    {
        id: 8,
        name: '张三',
        age: 12,
        sex: '男',
        address: '安徽省合肥市肥西县',
        status: 1,
        email: 'zhangsan@example.com',
        phone: '13800138001',
        company: '科技有限公司',
        position: '前端开发',
    },
    {
        id: 9,
        name: '李四',
        age: 18,
        sex: '男',
        address: '安徽省合肥市肥西县',
        status: 1,
        email: 'lisi@example.com',
        phone: '13800138002',
        company: '互联网公司',
        position: '后端开发',
    },
    {
        id: 10,
        name: '王二',
        age: 28,
        sex: '男',
        address: '安徽省合肥市肥西县',
        status: 1,
        email: 'wangwu@example.com',
        phone: '13800138003',
        company: '金融科技',
        position: '产品经理',
    },
    {
        id: 11,
        name: '麻子',
        age: 17,
        sex: '男',
        address: '内蒙古自治区呼伦贝尔市莫力达瓦达幹尔自治旗',
        status: 0,
        email: 'mazi@example.com',
        phone: '13800138004',
        company: '电子商务',
        position: '设计师',
    },
    {
        id: 12,
        name: '丧彪',
        age: 80,
        sex: '男',
        address: '地府',
        status: 0,
        email: 'sangbiao@example.com',
        phone: '13800138005',
        company: '冥界科技',
        position: 'CEO',
    },
    {
        id: 13,
        name: '奥德彪',
        age: 23,
        sex: '男',
        address: '非洲',
        status: 0,
        email: 'aodebiao@example.com',
        phone: '13800138006',
        company: '国际贸易',
        position: '销售经理',
    },
    {
        id: 14,
        name: '宙斯',
        age: 33,
        sex: '男',
        address: '宇宙太阳系',
        status: 0,
        email: 'zeus@example.com',
        phone: '13800138007',
        company: '奥林匹斯集团',
        position: '众神之王',
    },
]);

Sorting ​

html
<hy-table :data="tableData" :columns="columns" :height="500" @sort-change="handleSort"></hy-table>

<script setup lang="ts">
    import { ref } from 'vue';
    const columns = ref([
        { title: '姓名', key: 'name', width: 120 },
        { title: '年龄', key: 'age', width: 100, sortable: true },
        { title: '入职时间', key: 'joinDate', width: 150, sortable: true },
    ]);

    const handleSort = (field: string, order: string) => {
        console.log('排序字段:', field, '排序顺序:', order);
        // You can request sorted data from the backend here
    };
</script>

Custom Empty State ​

html
<hy-table :data="emptyData" :columns="columns" :height="500">
    <template #empty>
        <view class="custom-empty">
            <image
                src="/static/empty.png"
                mode="aspectFit"
                style="width: 120rpx; height: 120rpx;"
            ></image>
            <text>暂无数据,请点击添加</text>
            <button @click="addData">添加数据</button>
        </view>
    </template>
</hy-table>

Loading State ​

html
<hy-table :data="tableData" :columns="columns" :height="500" :loading="loading"></hy-table>

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

    const loading = ref(true)
    const tableData = ref([])

    onMounted(async () => {
      // Simulate asynchronous loading
      loading.value = true
      await new Promise(resolve => setTimeout(resolve, 2000))
      tableData.value = [...]
      loading.value = false
    })
</script>

Style Customization ​

Custom Theme ​

You can customize the table style by overriding CSS variables:

scss
:root {
    --hy-table-header-bg: #f5f7fa;
    --hy-table-header-text-color: #333;
    --hy-table-stripe-bg: #fafafa;
    --hy-table-border-color: #e8e8e8;
}

API ​

Table Props ​

PropDescriptionTypeDefault Value
dataTable data sourceArray-
columnsColumn configurationITableColumn[]-
heightTable height; supports a number or a string with a unit, numbers default to pxstring|number400
rowHeightRow height; supports a number or a string with a unit, numbers default to pxstring|number50
stripeWhether to show striped rowsbooleanfalse
borderWhether to show horizontal bordersbooleantrue
loadingWhether to show the loading statebooleanfalse
rowKeyUnique key field of row datastringid
showHeaderWhether to show the table headerbooleantrue
emptyUrlImage URL for the empty statestring-
emptyDesDescription text for the empty statestring-

Events ​

Event NameDescriptionCallback Parameters
sort-changeTriggered when the sort condition changessortField: String, sortOrder: SortType
row-clickTriggered when a row is clickedrow: Object, index: Number

Slots ​

Column Header Slots ​

Slot NameDescriptionParameters
left-headHeader slot for the left fixed columnscol: column configuration object
headHeader slot for the middle scrollable columnscol: column configuration object
right-headHeader slot for the right fixed columnscol: column configuration object

Content Slots ​

Slot NameDescriptionParameters
leftContent slot for the left fixed columnsrow: row data, col: column configuration, index: row index
defaultContent slot for the middle scrollable columnsrow: row data, col: column configuration, index: row index
rightContent slot for the right fixed columnsrow: row data, col: column configuration, index: row index

Other Slots ​

Slot NameDescription
emptyCustom empty state

Typings ​

Type Definitions
ts
export interface ITableColumn {
    /** Column title */
    title: string;
    /** Corresponding data field name */
    key: string;
    /** Column width (numbers default to px) */
    width: number;
    /** Alignment */
    align?: HyApp.RowCenterType;
    /** Whether sorting is enabled */
    sortable?: boolean;
    /** Whether to enable ellipsis for overly long text */
    ellipsis?: boolean;
    /** When ellipsis is enabled, whether to show the full content on tap (Tooltip) */
    tooltip?: boolean;
    /** Whether the column is fixed ('left' | 'right') */
    fixed?: 'left' | 'right';
    /** Data processing function */
    formatter?: (value: any, row: any) => string;
}

export type SortType = 'asc' | 'desc' | 'normal';

CSS Variables ​

Variable NameDescriptionDefault Value
--hy-table-header-text-colorHeader text color#909399
--hy-table-stripe-bgStriped row background colorFollows --hy-background--table-header
--hy-table-header-heightHeader height50px
--hy-table-header-cell-paddingHeader cell padding0 20rpx
--hy-table-header-cell-font-sizeHeader cell font size28rpx
--hy-table-cell-paddingContent cell padding0 8px
--hy-table-cell-font-sizeContent cell font size14px
--hy-table-fixed-left-shadowFixed column shadow (left side)4px 0 10px rgba(0, 0, 0, 0.1)
--hy-table-fixed-right-shadowFixed column shadow (right side)-4px 0 10px rgba(0, 0, 0, 0.1)
--hy-table-borderTable border (including cell dividers, synchronized in 8 places)Follows --hy-border-line
12:33
battery