Skip to content

表格 Table

展示行列数据

何时使用

  • 当有大量结构化的数据需要展现时
  • 当需要对数据进行排序、搜索、分页、自定义操作等复杂行为时

基本使用

NameAgeJobSexAddressAction
hello Stephen Curry30Player
boy
Chase Center, San Francisco, CaliforniaInvite Stephen Curry
Delete
hello the Muse Catcher24None
boy
Beijing, ChinaInvite the Muse Catcher
Delete
hello Wonder Woman32Hero
girl
Tel Aviv, IsraelInvite Wonder Woman
Delete
hello Superman32Hero
boy
United StatesInvite Superman
Delete
hello Leo36Actor
boy
Los AngelesInvite Leo
Delete
共 5 条 1
Show Code
vue
<script setup lang="ts">
import { ref, reactive, onBeforeMount } from 'vue'
import { SmileOutlined } from '@ant-design/icons-vue'
import type { TableColumn } from 'vue-amazing-ui'
const loading = ref<boolean>(false)
const queryParams = reactive({
  pageSize: 10,
  page: 1
})
const columns = reactive<TableColumn[]>([
  {
    title: 'Name',
    width: 100,
    dataIndex: 'name',
    key: 'name'
  },
  {
    title: 'Age',
    width: 60,
    dataIndex: 'age'
  },
  {
    title: 'Job',
    width: 80,
    dataIndex: 'job',
    key: 'job'
  },
  {
    title: 'Sex',
    width: 60,
    dataIndex: 'sex',
    key: 'sex'
  },
  {
    title: 'Address',
    width: 120,
    dataIndex: 'address'
  },
  {
    title: 'Action',
    width: 150,
    key: 'action'
  }
])
const dataSource = ref([
  {
    name: 'Stephen Curry',
    age: 30,
    job: 'Player',
    sex: 'boy',
    address: 'Chase Center, San Francisco, California'
  },
  {
    name: 'the Muse Catcher',
    age: 24,
    job: 'None',
    sex: 'boy',
    address: 'Beijing, China'
  },
  {
    name: 'Wonder Woman',
    age: 32,
    job: 'Hero',
    sex: 'girl',
    address: 'Tel Aviv, Israel'
  },
  {
    name: 'Superman',
    age: 32,
    job: 'Hero',
    sex: 'boy',
    address: 'United States'
  },
  {
    name: 'Leo',
    age: 36,
    job: 'Actor',
    sex: 'boy',
    address: 'Los Angeles'
  }
])
onBeforeMount(() => {
  getData()
})
function getData() {
  loading.value = true
  // 模拟异步请求获取数据
  setTimeout(() => {
    loading.value = false
  }, 1500)
}
function onChange(page: number, pageSize: number) {
  queryParams.page = page
  queryParams.pageSize = pageSize
  getData()
}
</script>
<template>
  <Table
    :columns="columns"
    :dataSource="dataSource"
    :pagination="{
      showTotal: true
    }"
    :loading="loading"
    @change="onChange"
  >
    <template #headerCell="{ column, title }">
      <template v-if="column.key === 'name'"> <SmileOutlined /> {{ title }} </template>
    </template>
    <template #bodyCell="{ column, record }">
      <template v-if="column.key === 'name'">
        <a> hello {{ record.name }} </a>
      </template>
      <template v-else-if="column.key === 'sex'">
        <Tag v-if="record.sex === 'boy'" color="volcano">{{ record.sex }}</Tag>
        <Tag v-else-if="record.sex === 'girl'" color="magenta">{{ record.sex }}</Tag>
      </template>
      <template v-else-if="column.key === 'action'">
        <span>
          <a>Invite {{ record.name }}</a>
          <Divider vertical />
          <a>Delete</a>
        </span>
      </template>
    </template>
  </Table>
</template>

加载中

NameAgeJobSexAddressAction

暂无数据

1 0
NameAgeJobSexAddressAction

暂无数据

1 0
Show Code
vue
<script setup lang="ts">
import { reactive } from 'vue'
import type { TableColumn } from 'vue-amazing-ui'
const columns = reactive<TableColumn[]>([
  {
    title: 'Name',
    width: 100,
    dataIndex: 'name',
    key: 'name'
  },
  {
    title: 'Age',
    width: 60,
    dataIndex: 'age'
  },
  {
    title: 'Job',
    width: 80,
    dataIndex: 'job',
    key: 'job'
  },
  {
    title: 'Sex',
    width: 60,
    dataIndex: 'sex',
    key: 'sex'
  },
  {
    title: 'Address',
    width: 120,
    dataIndex: 'address'
  },
  {
    title: 'Action',
    width: 150,
    key: 'action'
  }
])
</script>
<template>
  <Flex vertical>
    <Table :columns="columns" loading />
    <Table :columns="columns" loading :spin-props="{ indicator: 'dynamic-circle' }" />
  </Flex>
</template>

暂无数据

NameAgeJobSexAddressAction

暂无数据

1 0
NameAgeJobSexAddressAction

no data

1 0
Show Code
vue
<script setup lang="ts">
import { reactive } from 'vue'
import type { TableColumn } from 'vue-amazing-ui'
const columns = reactive<TableColumn[]>([
  {
    title: 'Name',
    width: 100,
    dataIndex: 'name',
    key: 'name'
  },
  {
    title: 'Age',
    width: 60,
    dataIndex: 'age'
  },
  {
    title: 'Job',
    width: 80,
    dataIndex: 'job',
    key: 'job'
  },
  {
    title: 'Sex',
    width: 60,
    dataIndex: 'sex',
    key: 'sex'
  },
  {
    title: 'Address',
    width: 120,
    dataIndex: 'address'
  },
  {
    title: 'Action',
    width: 150,
    key: 'action'
  }
])
</script>
<template>
  <Flex vertical>
    <Table :columns="columns" />
    <Table :columns="columns" :empty-props="{ description: 'no data', image: 'filled' }" />
  </Flex>
</template>

带边框

NameAgeJobSexAddressAction
hello Stephen Curry30Player
boy
Chase Center, San Francisco, CaliforniaInvite Stephen Curry
Delete
hello the Muse Catcher24None
boy
Beijing, ChinaInvite the Muse Catcher
Delete
hello Wonder Woman32Hero
girl
Tel Aviv, IsraelInvite Wonder Woman
Delete
hello Superman32Hero
boy
United StatesInvite Superman
Delete
hello Leo36Actor
boy
Los AngelesInvite Leo
Delete
共 5 条 1
Show Code
vue
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { SmileOutlined } from '@ant-design/icons-vue'
import type { TableColumn } from 'vue-amazing-ui'
const columns = reactive<TableColumn[]>([
  {
    title: 'Name',
    width: 100,
    dataIndex: 'name',
    key: 'name'
  },
  {
    title: 'Age',
    width: 60,
    dataIndex: 'age'
  },
  {
    title: 'Job',
    width: 80,
    dataIndex: 'job',
    key: 'job'
  },
  {
    title: 'Sex',
    width: 60,
    dataIndex: 'sex',
    key: 'sex'
  },
  {
    title: 'Address',
    width: 120,
    dataIndex: 'address'
  },
  {
    title: 'Action',
    width: 150,
    key: 'action'
  }
])
const dataSource = ref([
  {
    name: 'Stephen Curry',
    age: 30,
    job: 'Player',
    sex: 'boy',
    address: 'Chase Center, San Francisco, California'
  },
  {
    name: 'the Muse Catcher',
    age: 24,
    job: 'None',
    sex: 'boy',
    address: 'Beijing, China'
  },
  {
    name: 'Wonder Woman',
    age: 32,
    job: 'Hero',
    sex: 'girl',
    address: 'Tel Aviv, Israel'
  },
  {
    name: 'Superman',
    age: 32,
    job: 'Hero',
    sex: 'boy',
    address: 'United States'
  },
  {
    name: 'Leo',
    age: 36,
    job: 'Actor',
    sex: 'boy',
    address: 'Los Angeles'
  }
])
</script>
<template>
  <Table
    :columns="columns"
    :data-source="dataSource"
    :pagination="{
      showTotal: true
    }"
    bordered
  >
    <template #headerCell="{ column, title }">
      <template v-if="column.key === 'name'"> <SmileOutlined /> {{ title }} </template>
    </template>
    <template #bodyCell="{ column, record }">
      <template v-if="column.key === 'name'">
        <a> hello {{ record.name }} </a>
      </template>
      <template v-else-if="column.key === 'sex'">
        <Tag v-if="record.sex === 'boy'" color="volcano">{{ record.sex }}</Tag>
        <Tag v-else-if="record.sex === 'girl'" color="magenta">{{ record.sex }}</Tag>
      </template>
      <template v-else-if="column.key === 'action'">
        <span>
          <a>Invite {{ record.name }}</a>
          <Divider vertical />
          <a>Delete</a>
        </span>
      </template>
    </template>
  </Table>
</template>

自定义样式

使用 rowClassNameColumn.className 自定义表格样式


bordered:
NameAgeJobAddress
Stephen Curry30PlayerChase Center, GSW
the Muse Catcher24NoneBeijing, China
Wonder Woman32HeroTel Aviv, Israel
1
Show Code
vue
<script setup lang="ts">
import { ref, reactive } from 'vue'
import type { TableColumn } from 'vue-amazing-ui'
const customStyleBordered = ref<boolean>(true)
const columnsCustomStyle = reactive<TableColumn[]>([
  { title: 'Name', dataIndex: 'name' },
  { title: 'Age', dataIndex: 'age', className: 'age' },
  { title: 'Job', dataIndex: 'job' },
  { title: 'Address', dataIndex: 'address' }
])
const dataSourceCustomStyle = ref([
  {
    key: '1',
    name: 'Stephen Curry',
    age: 30,
    job: 'Player',
    address: 'Chase Center, GSW'
  },
  {
    key: '2',
    name: 'the Muse Catcher',
    age: 24,
    job: 'None',
    address: 'Beijing, China'
  },
  {
    key: '3',
    name: 'Wonder Woman',
    age: 32,
    job: 'Hero',
    address: 'Tel Aviv, Israel'
  }
])
const rowClassName = (record: any, rowIndex: number) => {
  if (record.age > 30) {
    return 'older-row'
  } else if (rowIndex % 2 === 1) {
    return 'even-row'
  }
  return ''
}
</script>
<template>
  <Flex vertical>
    <Space align="center"> bordered: <Switch v-model="customStyleBordered" /> </Space>
    <Table
      :columns="columnsCustomStyle"
      :data-source="dataSourceCustomStyle"
      :row-class-name="rowClassName"
      :bordered="customStyleBordered"
    />
  </Flex>
</template>
<style lang="less" scoped>
:deep(.even-row td) {
  color: #1677ff !important;
}
:deep(.age) {
  color: #09c8ce !important;
}
:deep(.older-row .age) {
  color: #eb2f96 !important;
}
</style>

三种尺寸

另两种紧凑型的列表;小型列表适用于对话框内


bordered:
size:
small
middle
large
NameAgeAddress
Stephen Curry30Chase Center, GSW
the Muse Catcher24Beijing, China
Wonder Woman32Tel Aviv, Israel
1
Show Code
vue
<script setup lang="ts">
import { ref, reactive } from 'vue'
import type { TableProps, TableColumn } from 'vue-amazing-ui'
const sizeBordered = ref<boolean>(true)
const sizeOptions = [
  {
    label: 'small',
    value: 'small'
  },
  {
    label: 'middle',
    value: 'middle'
  },
  {
    label: 'large',
    value: 'large'
  }
]
const size = ref<TableProps['size']>('middle')
const columnsSize = reactive<TableColumn[]>([
  { title: 'Name', dataIndex: 'name' },
  { title: 'Age', dataIndex: 'age' },
  { title: 'Address', dataIndex: 'address' }
])
const dataSourceSize = ref([
  {
    key: '1',
    name: 'Stephen Curry',
    age: 30,
    address: 'Chase Center, GSW'
  },
  {
    key: '2',
    name: 'the Muse Catcher',
    age: 24,
    address: 'Beijing, China'
  },
  {
    key: '3',
    name: 'Wonder Woman',
    age: 32,
    address: 'Tel Aviv, Israel'
  }
])
</script>
<template>
  <Flex vertical>
    <Space align="center"> bordered: <Switch v-model="sizeBordered" /> </Space>
    <Space align="center"> size: <Radio :options="sizeOptions" v-model:value="size" button button-style="solid" /> </Space>
    <Table :columns="columnsSize" :data-source="dataSourceSize" :bordered="sizeBordered" :size="size" />
  </Flex>
</template>

列对齐方式

bordered:
align:
left
center
right
NameAgeAddress
Stephen Curry30Chase Center, GSW
the Muse Catcher24Beijing, China
Wonder Woman32Tel Aviv, Israel
1
Show Code
vue
<script setup lang="ts">
import { ref, reactive, watch } from 'vue'
import type { TableColumn } from 'vue-amazing-ui'
const alignBordered = ref<boolean>(true)
const alignOptions = [
  {
    label: 'left',
    value: 'left'
  },
  {
    label: 'center',
    value: 'center'
  },
  {
    label: 'right',
    value: 'right'
  }
]
const align = ref<TableColumn['align']>('center')
const columnsAlign = reactive<TableColumn[]>([
  { title: 'Name', align: 'center', dataIndex: 'name' },
  { title: 'Age', align: 'center', dataIndex: 'age' },
  { title: 'Address', align: 'center', dataIndex: 'address' }
])
watch(align, () => {
  columnsAlign.forEach((column: TableColumn) => (column.align = align.value))
})
const dataSourceAlign = ref([
  {
    key: '1',
    name: 'Stephen Curry',
    age: 30,
    address: 'Chase Center, GSW'
  },
  {
    key: '2',
    name: 'the Muse Catcher',
    age: 24,
    address: 'Beijing, China'
  },
  {
    key: '3',
    name: 'Wonder Woman',
    age: 32,
    address: 'Tel Aviv, Israel'
  }
])
</script>
<template>
  <Flex vertical>
    <Space align="center"> bordered: <Switch v-model="alignBordered" /> </Space>
    <Space align="center"> align: <Radio :options="alignOptions" v-model:value="align" button button-style="solid" /> </Space>
    <Table :columns="columnsAlign" :data-source="dataSourceAlign" :bordered="alignBordered" />
  </Flex>
</template>

斑马条纹

bordered:
NameAgeJobAddress
Stephen Curry30PlayerChase Center, San Francisco, California
the Muse Catcher24NoneBeijing, China
Wonder Woman32HeroTel Aviv, Israel
Superman32HeroUnited States
Leo36ActorLos Angeles
1
Show Code
vue
<script setup lang="ts">
import { ref, reactive } from 'vue'
import type { TableColumn } from 'vue-amazing-ui'
const stripedBordered = ref<boolean>(true)
const columnsStriped = reactive<TableColumn[]>([
  {
    title: 'Name',
    dataIndex: 'name'
  },
  {
    title: 'Age',
    dataIndex: 'age'
  },
  {
    title: 'Job',
    dataIndex: 'job'
  },
  {
    title: 'Address',
    dataIndex: 'address'
  }
])
const dataSourcesStriped = ref([
  {
    name: 'Stephen Curry',
    age: 30,
    job: 'Player',
    address: 'Chase Center, San Francisco, California'
  },
  {
    name: 'the Muse Catcher',
    age: 24,
    job: 'None',
    address: 'Beijing, China'
  },
  {
    name: 'Wonder Woman',
    age: 32,
    job: 'Hero',
    address: 'Tel Aviv, Israel'
  },
  {
    name: 'Superman',
    age: 32,
    job: 'Hero',
    address: 'United States'
  },
  {
    name: 'Leo',
    age: 36,
    job: 'Actor',
    address: 'Los Angeles'
  }
])
</script>
<template>
  <Flex vertical>
    <Space align="center"> bordered: <Switch v-model="stripedBordered" /> </Space>
    <Table :columns="columnsStriped" :data-source="dataSourcesStriped" striped :bordered="stripedBordered" />
  </Flex>
</template>

页头和页脚

bordered:
Header firstData name: Stephen Curry
NameAgeJobSexAddressAction
hello Stephen Curry30Player
boy
Chase Center, San Francisco, CaliforniaInvite
Delete
hello the Muse Catcher24None
boy
Beijing, ChinaInvite
Delete
hello Wonder Woman32Hero
girl
Tel Aviv, IsraelInvite
Delete
hello Superman32Hero
boy
United StatesInvite
Delete
hello Leo36Actor
boy
Los AngelesInvite
Delete
1
Show Code
vue
<script setup lang="ts">
import { ref, reactive } from 'vue'
import type { TableColumn } from 'vue-amazing-ui'
const headerFooterbordered = ref<boolean>(true)
const columns = reactive<TableColumn[]>([
  {
    title: 'Name',
    width: 100,
    dataIndex: 'name',
    key: 'name'
  },
  {
    title: 'Age',
    width: 60,
    dataIndex: 'age'
  },
  {
    title: 'Job',
    width: 80,
    dataIndex: 'job',
    key: 'job'
  },
  {
    title: 'Sex',
    width: 60,
    dataIndex: 'sex',
    key: 'sex'
  },
  {
    title: 'Address',
    width: 120,
    dataIndex: 'address'
  },
  {
    title: 'Action',
    width: 150,
    key: 'action'
  }
])
const dataSource = ref([
  {
    name: 'Stephen Curry',
    age: 30,
    job: 'Player',
    sex: 'boy',
    address: 'Chase Center, San Francisco, California'
  },
  {
    name: 'the Muse Catcher',
    age: 24,
    job: 'None',
    sex: 'boy',
    address: 'Beijing, China'
  },
  {
    name: 'Wonder Woman',
    age: 32,
    job: 'Hero',
    sex: 'girl',
    address: 'Tel Aviv, Israel'
  },
  {
    name: 'Superman',
    age: 32,
    job: 'Hero',
    sex: 'boy',
    address: 'United States'
  },
  {
    name: 'Leo',
    age: 36,
    job: 'Actor',
    sex: 'boy',
    address: 'Los Angeles'
  }
])
</script>
<template>
  <Flex vertical>
    <Space align="center"> bordered: <Switch v-model="headerFooterbordered" /> </Space>
    <Table :columns="columns" :data-source="dataSource" :bordered="headerFooterbordered">
      <template #header> Header firstData name: {{ dataSource[0].name }} </template>
      <template #bodyCell="{ column, text }">
        <template v-if="column.key === 'name'">
          <a> hello {{ text }} </a>
        </template>
        <template v-else-if="column.key === 'sex'">
          <Tag v-if="text === 'boy'" color="volcano">{{ text }}</Tag>
          <Tag v-else-if="text === 'girl'" color="magenta">{{ text }}</Tag>
        </template>
        <template v-else-if="column.key === 'action'">
          <span>
            <a>Invite</a>
            <Divider vertical />
            <a>Delete</a>
          </span>
        </template>
      </template>
      <template #footer> Footer lastData name: {{ dataSource[dataSource.length - 1].name }} </template>
    </Table>
  </Flex>
</template>

单元格自动省略

设置 column.ellipsis 可以让单元格内容根据宽度自动省略


1
Show Code
vue
<script setup lang="ts">
import { ref, reactive } from 'vue'
import type { TableColumn } from 'vue-amazing-ui'
const columnsEllipsis = reactive<TableColumn[]>([
  {
    title: 'Name',
    dataIndex: 'name'
  },
  {
    title: 'Age',
    dataIndex: 'age',
    width: 80
  },
  {
    title: 'Address',
    dataIndex: 'address',
    ellipsis: true
  },
  {
    title: 'Long Header Cell Long Header Cell',
    dataIndex: 'address',
    ellipsis: true
  },
  {
    title: 'Long Header Cell',
    dataIndex: 'address',
    ellipsis: true
  },
  {
    title: 'Long Header Cell',
    dataIndex: 'address',
    ellipsis: true
  }
])
const dataSource = ref([
  {
    name: 'Stephen Curry',
    age: 30,
    job: 'Player',
    sex: 'boy',
    address: 'Chase Center, San Francisco, California'
  },
  {
    name: 'the Muse Catcher',
    age: 24,
    job: 'None',
    sex: 'boy',
    address: 'Beijing, China'
  },
  {
    name: 'Wonder Woman',
    age: 32,
    job: 'Hero',
    sex: 'girl',
    address: 'Tel Aviv, Israel'
  },
  {
    name: 'Superman',
    age: 32,
    job: 'Hero',
    sex: 'boy',
    address: 'United States'
  },
  {
    name: 'Leo',
    age: 36,
    job: 'Actor',
    sex: 'boy',
    address: 'Los Angeles'
  }
])
</script>
<template>
  <Table :columns="columnsEllipsis" :data-source="dataSource">
    <template #bodyCell="{ column, text }">
      <template v-if="column.dataIndex === 'name'">
        <a>{{ text }}</a>
      </template>
    </template>
  </Table>
</template>

合并单元格

表头只支持列合并,使用 column 里的 colSpan 进行设置;表格支持行/列合并,使用 customCell 将单元格属性 colSpanrowSpan 设为 0 时,设置的表格不会渲染


NameAgeHome phoneAddress
Stephen Curry300666-1209890918889898989Chase Center, San Francisco, California
the Muse Catcher240666-2209833318899998888Beijing, China
Wonder Woman320888-32098909Tel Aviv, Israel
Superman32United States
Leo
1
Show Code
vue
<script setup lang="ts">
import { ref, reactive } from 'vue'
import type { TableColumn } from 'vue-amazing-ui'
const sharedOnCell = (record: any, index: number) => {
  if (index === 4) {
    return { colSpan: 0 }
  }
}
const columnsMerge = reactive<TableColumn[]>([
  {
    title: 'Name',
    dataIndex: 'name',
    customCell: (record: any, index: number) => {
      return {
        colSpan: index < 4 ? 1 : 5
      }
    }
  },
  {
    title: 'Age',
    dataIndex: 'age',
    customCell: sharedOnCell
  },
  {
    title: 'Home phone',
    colSpan: 2,
    dataIndex: 'tel',
    customCell: (record: any, index: number) => {
      if (index === 2) {
        return { rowSpan: 2 }
      }
      // These two are merged into above cell
      if (index === 3) {
        return { rowSpan: 0 }
      }
      if (index === 4) {
        return { colSpan: 0 }
      }
    }
  },
  {
    title: 'Phone',
    colSpan: 0,
    dataIndex: 'phone',
    customCell: (record: any, index: number) => {
      if (index === 1) {
        return { rowSpan: 3 }
      }
      if (index === 2) {
        return { rowSpan: 0 }
      }
      if (index === 3) {
        return { rowSpan: 0 }
      }
      if (index === 4) {
        return { colSpan: 0 }
      }
    }
  },
  {
    title: 'Address',
    dataIndex: 'address',
    customCell: sharedOnCell
  }
])
const dataSourceMerge = ref([
  {
    name: 'Stephen Curry',
    age: 30,
    tel: '0666-12098909',
    phone: 18889898989,
    address: 'Chase Center, San Francisco, California'
  },
  {
    name: 'the Muse Catcher',
    age: 24,
    tel: '0666-22098333',
    phone: 18899998888,
    address: 'Beijing, China'
  },
  {
    name: 'Wonder Woman',
    age: 32,
    tel: '0888-32098909',
    phone: 18899998888,
    address: 'Tel Aviv, Israel'
  },
  {
    name: 'Superman',
    age: 32,
    tel: '0888-32098909',
    phone: 18899998888,
    address: 'United States'
  },
  {
    name: 'Leo',
    age: 36,
    tel: '0575-22098909',
    phone: 18900010002,
    address: 'Los Angeles'
  }
])
</script>
<template>
  <Table :columns="columnsMerge" :data-source="dataSourceMerge" bordered>
    <template #bodyCell="{ column, text }">
      <template v-if="column.dataIndex === 'name'">
        <a href="javascript:;">{{ text }}</a>
      </template>
    </template>
  </Table>
</template>

可编辑单元格

新增
NameAgeAddressAction
Edward King 0
32London, Park Lane no. 0
Edward King 1
32London, Park Lane no. 1
Edward King 2
32London, Park Lane no. 2
1
Show Code
vue
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { PlusOutlined, CheckOutlined, EditOutlined } from '@ant-design/icons-vue'
import type { TableColumn } from 'vue-amazing-ui'
const columnsCellEditable = reactive<TableColumn[]>([
  {
    title: 'Name',
    dataIndex: 'name',
    width: '30%'
  },
  {
    title: 'Age',
    dataIndex: 'age'
  },
  {
    title: 'Address',
    dataIndex: 'address'
  },
  {
    title: 'Action',
    dataIndex: 'action'
  }
])
const dataSourceCellEditable = ref([
  {
    key: '0',
    name: 'Edward King 0',
    age: 32,
    address: 'London, Park Lane no. 0'
  },
  {
    key: '1',
    name: 'Edward King 1',
    age: 32,
    address: 'London, Park Lane no. 1'
  },
  {
    key: '2',
    name: 'Edward King 2',
    age: 32,
    address: 'London, Park Lane no. 2'
  }
])
const data: any[] = []
for (let i = 0; i < 100; i++) {
  data.push({
    key: i.toString(),
    name: `Edrward ${i}`,
    age: 32,
    address: `London, Park Lane no. ${i}`
  })
}
const cellEditableData = reactive<any>({})
const handleCellAdd = () => {
  const count = dataSourceCellEditable.value.length
  const newData = {
    key: `${count}`,
    name: `Edward King ${count}`,
    age: 32,
    address: `London, Park Lane no. ${count}`
  }
  dataSourceCellEditable.value.push(newData)
}
const handleCellEdit = (key: string) => {
  cellEditableData[key] = dataSourceCellEditable.value.filter((item) => key === item.key)[0]
}
const handleCellSave = (key: string) => {
  Object.assign(dataSourceCellEditable.value.filter((item) => key === item.key)[0], cellEditableData[key])
  delete cellEditableData[key]
}
const handleCellDelete = (key: string) => {
  dataSourceCellEditable.value = dataSourceCellEditable.value.filter((item) => item.key !== key)
}
</script>
<template>
  <Button style="margin-bottom: 16px" type="primary" :icon="() => h(PlusOutlined)" @click="handleCellAdd">新增</Button>
  <Table :columns="columnsCellEditable" :data-source="dataSourceCellEditable" bordered>
    <template #bodyCell="{ column, text, record }">
      <template v-if="column.dataIndex === 'name'">
        <div class="editable-cell">
          <Flex v-if="cellEditableData[record.key]" justify="space-between" align="center">
            <Input v-model:value="cellEditableData[record.key].name" @enter="handleCellSave(record.key)" />
            <CheckOutlined class="cell-icon-check" @click="handleCellSave(record.key)" />
          </Flex>
          <Flex v-else justify="space-between" align="center">
            {{ text || ' ' }}
            <EditOutlined class="cell-icon" @click="handleCellEdit(record.key)" />
          </Flex>
        </div>
      </template>
      <template v-else-if="column.dataIndex === 'action'">
        <Popconfirm v-if="dataSourceCellEditable.length" title="Sure to delete?" @ok="handleCellDelete(record.key)">
          <a>delete</a>
        </Popconfirm>
      </template>
    </template>
  </Table>
</template>
<style lang="less" scoped>
.editable-cell {
  .cell-icon {
    display: none;
  }
  .cell-icon,
  .cell-icon-check {
    &:hover {
      transition: color 0.3s;
      color: #1890ff;
    }
  }
  &:hover {
    .cell-icon {
      display: inline-block;
    }
  }
}
</style>

可编辑行

NameAgeAddressAction
Edrward 032London, Park Lane no. 0Edit
Edrward 132London, Park Lane no. 1Edit
Edrward 232London, Park Lane no. 2Edit
Edrward 332London, Park Lane no. 3Edit
Edrward 432London, Park Lane no. 4Edit
Edrward 532London, Park Lane no. 5Edit
Edrward 632London, Park Lane no. 6Edit
Edrward 732London, Park Lane no. 7Edit
Edrward 832London, Park Lane no. 8Edit
Edrward 932London, Park Lane no. 9Edit
1 2345•••10
10 条/页
Show Code
vue
<script setup lang="ts">
import { ref, reactive } from 'vue'
import type { TableColumn } from 'vue-amazing-ui'
const tableLoading = ref<boolean>(false)
const columnsRowEditable = reactive<TableColumn[]>([
  {
    title: 'Name',
    dataIndex: 'name',
    width: '25%'
  },
  {
    title: 'Age',
    dataIndex: 'age',
    width: '15%'
  },
  {
    title: 'Address',
    dataIndex: 'address',
    width: '40%'
  },
  {
    title: 'Action',
    dataIndex: 'action'
  }
])
const data: any[] = []
for (let i = 0; i < 100; i++) {
  data.push({
    key: i.toString(),
    name: `Edrward ${i}`,
    age: 32,
    address: `London, Park Lane no. ${i}`
  })
}
const dataSourceRowEditable = ref<any[]>(data.slice(0, 10))
const rowEditableData = reactive<any>({})
const handleRowEdit = (key: string) => {
  rowEditableData[key] = dataSourceRowEditable.value.filter((item) => key === item.key)[0]
}
const handleRowSave = (key: string) => {
  Object.assign(dataSourceCellEditable.value.filter((item) => key === item.key)[0], rowEditableData[key])
  delete rowEditableData[key]
}
const handleRowCancel = (key: string) => {
  delete rowEditableData[key]
}
const handleTableChange = (page: number, pageSize: number) => {
  tableLoading.value = true
  setTimeout(() => {
    dataSourceRowEditable.value = data.slice((page - 1) * pageSize, page * pageSize)
    tableLoading.value = false
  }, 500)
}
</script>
<template>
  <Table
    :columns="columnsRowEditable"
    :data-source="dataSourceRowEditable"
    bordered
    :loading="tableLoading"
    :pagination="{
      total: 100
    }"
    @change="handleTableChange"
  >
    <template #bodyCell="{ column, text, record }">
      <template v-if="['name', 'address'].includes(column.dataIndex)">
        <Input
          v-if="rowEditableData[record.key]"
          v-model:value="rowEditableData[record.key][column.dataIndex]"
          style="margin: -5px 0"
        />
        <template v-else>
          {{ text }}
        </template>
      </template>
      <template v-else-if="column.dataIndex === 'age'">
        <InputNumber
          v-if="rowEditableData[record.key]"
          width="100%"
          v-model:value="rowEditableData[record.key][column.dataIndex]"
          style="margin: -5px 0"
        />
        <template v-else>
          {{ text }}
        </template>
      </template>
      <template v-else-if="column.dataIndex === 'action'">
        <span v-if="rowEditableData[record.key]">
          <a @click="handleRowSave(record.key)">Save</a>
          <Divider vertical />
          <Popconfirm title="Sure to cancel?" @ok="handleRowCancel(record.key)">
            <a>Cancel</a>
          </Popconfirm>
        </span>
        <span v-else>
          <a @click="handleRowEdit(record.key)">Edit</a>
        </span>
      </template>
    </template>
  </Table>
</template>

可展开

当表格内容较多不能一次性完全展示时


MoreNameAgeAddressAction
Superman32New York No.1 Lake ParkDelete
My name is Superman, I am 32 years old, living in New York No.1 Lake Park.
Spiderman22London No.2 Lake ParkDelete
My name is Spiderman, I am 42 years old, living in London No.2 Lake Park.
Ironman36Sidney No.3 Lake ParkDelete
My name is Ironman, I am 32 years old, living in Sidney No.3 Lake Park.
1
Show Code
vue
<script setup lang="ts">
import { ref, reactive, watchEffect } from 'vue'
import type { TableProps, TableColumn } from 'vue-amazing-ui'
const columnsExpandable = reactive<TableColumn[]>([
  { title: 'Name', dataIndex: 'name', key: 'name' },
  { title: 'Age', dataIndex: 'age', key: 'age' },
  { title: 'Address', dataIndex: 'address', key: 'address' },
  { title: 'Action', key: 'action' }
])
const dataSourceExpandable = ref([
  {
    key: '1',
    name: 'Superman',
    age: 32,
    address: 'New York No.1 Lake Park',
    description: 'My name is Superman, I am 32 years old, living in New York No.1 Lake Park.'
  },
  {
    key: '2',
    name: 'Spiderman',
    age: 22,
    address: 'London No.2 Lake Park',
    description: 'My name is Spiderman, I am 42 years old, living in London No.2 Lake Park.'
  },
  {
    key: '3',
    name: 'Ironman',
    age: 36,
    address: 'Sidney No.3 Lake Park',
    description: 'My name is Ironman, I am 32 years old, living in Sidney No.3 Lake Park.'
  }
])
const expandedRowKeys = ref<TableProps['expandedRowKeys']>(['1'])
watchEffect(() => {
  console.log('expandedRowKeys', expandedRowKeys.value)
})
const handleExpand = (expanded: boolean, record: any) => {
  console.log('expanded', expanded)
  console.log('record', record)
}
const handleExpandedRowsChange = (expandedRows: string[]) => {
  console.log('expandedRowsChange', expandedRows)
}
</script>
<template>
  <Table
    :columns="columnsExpandable"
    :data-source="dataSourceExpandable"
    :expand-column-width="100"
    showExpandColumn
    expandRowByClick
    expandFixed
    v-model:expandedRowKeys="expandedRowKeys"
    :scroll="{ x: 1600 }"
    @expand="handleExpand"
    @expandedRowsChange="handleExpandedRowsChange"
  >
    <template #expandedRowRender="{ record }">
      {{ record.description }}
    </template>
    <template #expandColumnTitle>
      <span style="color: #d4380d">More</span>
    </template>
    <template #bodyCell="{ column }">
      <template v-if="column.key === 'action'">
        <a>Delete</a>
      </template>
    </template>
  </Table>
</template>

固定列

对于列数很多的数据,可以固定前后的列,横向滚动查看其它数据,需要和 scroll.x 配合使用建议指定 scroll.x 为大于表格宽度的固定值或百分比,且非固定列宽度之和不要超过 scroll.x


Full NameAgeColumn 1Column 2Column 3Column 4Column 5Column 6Column 7Column 8Action
Stephen Curry30Chase Center, GSWChase Center, GSWChase Center, GSWChase Center, GSWChase Center, GSWChase Center, GSWChase Center, GSWChase Center, GSWaction
the Muse Catcher24Beijing, ChinaBeijing, ChinaBeijing, ChinaBeijing, ChinaBeijing, ChinaBeijing, ChinaBeijing, ChinaBeijing, Chinaaction
Wonder Woman32Tel Aviv, IsraelTel Aviv, IsraelTel Aviv, IsraelTel Aviv, IsraelTel Aviv, IsraelTel Aviv, IsraelTel Aviv, IsraelTel Aviv, Israelaction
1
Show Code
vue
<script setup lang="ts">
import { ref, reactive } from 'vue'
import type { TableColumn } from 'vue-amazing-ui'
const columnsFixColumn = reactive<TableColumn[]>([
  { title: 'Full Name', width: 100, dataIndex: 'name', key: 'name', fixed: 'left' },
  { title: 'Age', width: 100, dataIndex: 'age', key: 'age', fixed: 'left' },
  { title: 'Column 1', dataIndex: 'address', key: '1' },
  { title: 'Column 2', dataIndex: 'address', key: '2' },
  { title: 'Column 3', dataIndex: 'address', key: '3' },
  { title: 'Column 4', dataIndex: 'address', key: '4' },
  { title: 'Column 5', dataIndex: 'address', key: '5' },
  { title: 'Column 6', dataIndex: 'address', key: '6' },
  { title: 'Column 7', dataIndex: 'address', key: '7' },
  { title: 'Column 8', dataIndex: 'address', key: '8' },
  {
    title: 'Action',
    key: 'action',
    fixed: 'right',
    width: 100
  }
])
const dataSourceFixColumn = ref([
  {
    key: '1',
    name: 'Stephen Curry',
    age: 30,
    address: 'Chase Center, GSW'
  },
  {
    key: '2',
    name: 'the Muse Catcher',
    age: 24,
    address: 'Beijing, China'
  },
  {
    key: '3',
    name: 'Wonder Woman',
    age: 32,
    address: 'Tel Aviv, Israel'
  }
])
</script>
<template>
  <Table :columns="columnsFixColumn" :data-source="dataSourceFixColumn" :scroll="{ x: 1600 }">
    <template #bodyCell="{ column }">
      <template v-if="column.key === 'action'">
        <a>action</a>
      </template>
    </template>
  </Table>
</template>

固定表头

方便一页内展示大量数据


NameAgeAddress
Edrward 032London, Park Lane no. 0
Edrward 132London, Park Lane no. 1
Edrward 232London, Park Lane no. 2
Edrward 332London, Park Lane no. 3
Edrward 432London, Park Lane no. 4
Edrward 532London, Park Lane no. 5
Edrward 632London, Park Lane no. 6
Edrward 732London, Park Lane no. 7
Edrward 832London, Park Lane no. 8
Edrward 932London, Park Lane no. 9
1 2345•••10
10 条/页
Show Code
vue
<script setup lang="ts">
import { ref, reactive } from 'vue'
import type { TableColumn } from 'vue-amazing-ui'
const columnsFixHeader = reactive<TableColumn[]>([
  {
    title: 'Name',
    dataIndex: 'name'
  },
  {
    title: 'Age',
    dataIndex: 'age'
  },
  {
    title: 'Address',
    dataIndex: 'address'
  }
])
const data: any[] = []
for (let i = 0; i < 100; i++) {
  data.push({
    key: i.toString(),
    name: `Edrward ${i}`,
    age: 32,
    address: `London, Park Lane no. ${i}`
  })
}
const dataSourceFixHeader = ref(data)
</script>
<template>
  <Table :columns="columnsFixHeader" :data-source="dataSourceFixHeader" :scroll="{ y: 240 }" />
</template>

固定头和列

适合同时展示有大量数据和数据列建议指定 scroll.x 为大于表格宽度的固定值或百分比,且非固定列宽度之和不要超过 scroll.x


Full NameAgeColumn 1Column 2Column 3Column 4Column 5Column 6Column 7Column 8Action
Edrward 032London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0action
Edrward 132London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1action
Edrward 232London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2action
Edrward 332London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3action
Edrward 432London, Park Lane no. 4London, Park Lane no. 4London, Park Lane no. 4London, Park Lane no. 4London, Park Lane no. 4London, Park Lane no. 4London, Park Lane no. 4London, Park Lane no. 4action
Edrward 532London, Park Lane no. 5London, Park Lane no. 5London, Park Lane no. 5London, Park Lane no. 5London, Park Lane no. 5London, Park Lane no. 5London, Park Lane no. 5London, Park Lane no. 5action
Edrward 632London, Park Lane no. 6London, Park Lane no. 6London, Park Lane no. 6London, Park Lane no. 6London, Park Lane no. 6London, Park Lane no. 6London, Park Lane no. 6London, Park Lane no. 6action
Edrward 732London, Park Lane no. 7London, Park Lane no. 7London, Park Lane no. 7London, Park Lane no. 7London, Park Lane no. 7London, Park Lane no. 7London, Park Lane no. 7London, Park Lane no. 7action
Edrward 832London, Park Lane no. 8London, Park Lane no. 8London, Park Lane no. 8London, Park Lane no. 8London, Park Lane no. 8London, Park Lane no. 8London, Park Lane no. 8London, Park Lane no. 8action
Edrward 932London, Park Lane no. 9London, Park Lane no. 9London, Park Lane no. 9London, Park Lane no. 9London, Park Lane no. 9London, Park Lane no. 9London, Park Lane no. 9London, Park Lane no. 9action
1 2345•••10
10 条/页
Show Code
vue
<script setup lang="ts">
import { ref, reactive } from 'vue'
import type { TableColumn } from 'vue-amazing-ui'
const columnsFixHeaderAndColumn = reactive<TableColumn[]>([
  { title: 'Full Name', width: 100, dataIndex: 'name', key: 'name', fixed: 'left' },
  { title: 'Age', width: 100, dataIndex: 'age', key: 'age', fixed: 'left' },
  { title: 'Column 1', dataIndex: 'address', key: '1', width: 150 },
  { title: 'Column 2', dataIndex: 'address', key: '2', width: 150 },
  { title: 'Column 3', dataIndex: 'address', key: '3', width: 150 },
  { title: 'Column 4', dataIndex: 'address', key: '4', width: 150 },
  { title: 'Column 5', dataIndex: 'address', key: '5', width: 150 },
  { title: 'Column 6', dataIndex: 'address', key: '6', width: 150 },
  { title: 'Column 7', dataIndex: 'address', key: '7', width: 150 },
  { title: 'Column 8', dataIndex: 'address', key: '8' },
  {
    title: 'Action',
    key: 'action',
    fixed: 'right',
    width: 100
  }
])
const data: any[] = []
for (let i = 0; i < 100; i++) {
  data.push({
    key: i.toString(),
    name: `Edrward ${i}`,
    age: 32,
    address: `London, Park Lane no. ${i}`
  })
}
const dataSourceFixHeaderAndColumn = ref(data)
</script>
<template>
  <Table
    :columns="columnsFixHeaderAndColumn"
    :data-source="dataSourceFixHeaderAndColumn"
    :scroll="{ x: 1500, y: 300 }"
  >
    <template #bodyCell="{ column }">
      <template v-if="column.key === 'action'">
        <a>action</a>
      </template>
    </template>
  </Table>
</template>

随页面滚动的固定表头和滚动条

对于长表格,可以设置跟随页面固定表头和滚动条,方便查看表头和使用滚动条


Full NameAgeColumn 1Column 2Column 3Column 4Column 5Column 6Column 7Column 8Action
Edrward 032London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0action
Edrward 132London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1action
Edrward 232London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2action
Edrward 332London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3action
Edrward 432London, Park Lane no. 4London, Park Lane no. 4London, Park Lane no. 4London, Park Lane no. 4London, Park Lane no. 4London, Park Lane no. 4London, Park Lane no. 4London, Park Lane no. 4action
Edrward 532London, Park Lane no. 5London, Park Lane no. 5London, Park Lane no. 5London, Park Lane no. 5London, Park Lane no. 5London, Park Lane no. 5London, Park Lane no. 5London, Park Lane no. 5action
Edrward 632London, Park Lane no. 6London, Park Lane no. 6London, Park Lane no. 6London, Park Lane no. 6London, Park Lane no. 6London, Park Lane no. 6London, Park Lane no. 6London, Park Lane no. 6action
Edrward 732London, Park Lane no. 7London, Park Lane no. 7London, Park Lane no. 7London, Park Lane no. 7London, Park Lane no. 7London, Park Lane no. 7London, Park Lane no. 7London, Park Lane no. 7action
Edrward 832London, Park Lane no. 8London, Park Lane no. 8London, Park Lane no. 8London, Park Lane no. 8London, Park Lane no. 8London, Park Lane no. 8London, Park Lane no. 8London, Park Lane no. 8action
Edrward 932London, Park Lane no. 9London, Park Lane no. 9London, Park Lane no. 9London, Park Lane no. 9London, Park Lane no. 9London, Park Lane no. 9London, Park Lane no. 9London, Park Lane no. 9action
1 2345•••10
10 条/页
Show Code
vue
<script setup lang="ts">
import { ref, reactive } from 'vue'
import type { TableColumn } from 'vue-amazing-ui'
const columnsFixHeaderAndScrollbar = reactive<TableColumn[]>([
  { title: 'Full Name', width: 100, dataIndex: 'name', key: 'name', fixed: 'left' },
  { title: 'Age', width: 100, dataIndex: 'age', key: 'age', fixed: 'left' },
  { title: 'Column 1', dataIndex: 'address', key: '1', width: 150 },
  { title: 'Column 2', dataIndex: 'address', key: '2', width: 150 },
  { title: 'Column 3', dataIndex: 'address', key: '3', width: 150 },
  { title: 'Column 4', dataIndex: 'address', key: '4', width: 150 },
  { title: 'Column 5', dataIndex: 'address', key: '5', width: 150 },
  { title: 'Column 6', dataIndex: 'address', key: '6', width: 150 },
  { title: 'Column 7', dataIndex: 'address', key: '7', width: 150 },
  { title: 'Column 8', dataIndex: 'address', key: '8' },
  {
    title: 'Action',
    key: 'action',
    fixed: 'right',
    width: 100
  }
])
const data: any[] = []
for (let i = 0; i < 100; i++) {
  data.push({
    key: i.toString(),
    name: `Edrward ${i}`,
    age: 32,
    address: `London, Park Lane no. ${i}`
  })
}
const dataSourceFixHeaderAndScrollbar = ref(data)
</script>
<template>
  <Table
    :columns="columnsFixHeaderAndScrollbar"
    :data-source="dataSourceFixHeaderAndScrollbar"
    sticky
    :scroll="{ x: 1500 }"
  >
    <template #bodyCell="{ column }">
      <template v-if="column.key === 'action'">
        <a>action</a>
      </template>
    </template>
  </Table>
</template>

表头分组

columns[n] 可以内嵌 children,以渲染分组表头


bordered:
NameOtherCompanyGender
AddressCompany AddressCompany Name
StreetBlock
BuildingDoor No.
John Brown9Lake ParkC02035Lake Street 42SoftLake CoM
John Brown9Lake ParkC12035Lake Street 42SoftLake CoM
John Brown0Lake ParkC22035Lake Street 42SoftLake CoM
John Brown10Lake ParkC32035Lake Street 42SoftLake CoM
John Brown1Lake ParkC42035Lake Street 42SoftLake CoM
John Brown2Lake ParkC52035Lake Street 42SoftLake CoM
John Brown10Lake ParkC62035Lake Street 42SoftLake CoM
John Brown0Lake ParkC72035Lake Street 42SoftLake CoM
John Brown3Lake ParkC82035Lake Street 42SoftLake CoM
John Brown3Lake ParkC92035Lake Street 42SoftLake CoM
1 2345•••10
10 条/页
Show Code
vue
<script setup lang="ts">
import { ref, reactive } from 'vue'
import type { TableColumn } from 'vue-amazing-ui'
const groupBordered = ref<boolean>(true)
const columnsHeaderGroup = reactive<TableColumn[]>([
  {
    title: 'Name',
    dataIndex: 'name',
    key: 'name',
    width: 100,
    fixed: 'left'
  },
  {
    title: 'Other',
    children: [
      {
        title: 'Age',
        dataIndex: 'age',
        key: 'age',
        width: 200,
        sorter: (a: any, b: any) => a.age - b.age
      },
      {
        title: 'Address',
        children: [
          {
            title: 'Street',
            dataIndex: 'street',
            key: 'street',
            width: 200
          },
          {
            title: 'Block',
            children: [
              {
                title: 'Building',
                dataIndex: 'building',
                key: 'building',
                width: 100
              },
              {
                title: 'Door No.',
                dataIndex: 'number',
                key: 'number',
                width: 100
              }
            ]
          }
        ]
      }
    ]
  },
  {
    title: 'Company',
    children: [
      {
        title: 'Company Address',
        dataIndex: 'companyAddress',
        key: 'companyAddress',
        width: 200
      },
      {
        title: 'Company Name',
        dataIndex: 'companyName',
        key: 'companyName',
        width: 200
      }
    ]
  },
  {
    title: 'Gender',
    dataIndex: 'gender',
    key: 'gender',
    width: 80,
    fixed: 'right'
  }
])
// 获取 0~10 之间的随机整数
function getRandomIntInclusive(min: number, max: number) {
  min = Math.ceil(min)
  max = Math.floor(max)
  return Math.floor(Math.random() * (max - min + 1)) + min //加 1 是因为包含 max
}
const dataSourceHeaderGroup = [...Array(100)].map((_, i) => ({
  key: i.toString(),
  name: 'John Brown',
  age: getRandomIntInclusive(0, 10),
  street: 'Lake Park',
  building: 'C' + i,
  number: 2035,
  companyAddress: 'Lake Street 42',
  companyName: 'SoftLake Co',
  gender: 'M'
}))
</script>
<template>
  <Flex vertical>
    <Space align="center"> bordered: <Switch v-model="groupBordered" /> </Space>
    <Table
      :columns="columnsHeaderGroup"
      :data-source="dataSourceHeaderGroup"
      :bordered="groupBordered"
      :scroll="{ x: 1500, y: 240 }"
    />
  </Flex>
</template>

表格排序

bordered:
John Brown32New York No.1 Lake Park
Jim Green42London No.1 Lake Park
Joe Black32Sidney No.12 Lake Park
Jim Red32London No.102 Lake Park
1
Show Code
vue
<script setup lang="ts">
import { ref, reactive } from 'vue'
import type { TableColumn } from 'vue-amazing-ui'
const sortBordered = ref<boolean>(true)
const columnsSort = reactive<TableColumn[]>([
  {
    title: 'Name',
    dataIndex: 'name',
    sorter: (a: any, b: any) => a.name.length - b.name.length,
    sortDirections: ['descend']
  },
  {
    title: 'Age',
    dataIndex: 'age',
    defaultSortOrder: 'descend',
    sorter: (a: any, b: any) => a.age - b.age
  },
  {
    title: 'Address',
    dataIndex: 'address',
    sorter: (a: any, b: any) => a.address.length - b.address.length,
    sortDirections: ['descend', 'ascend']
  }
])
const dataSourceSort = ref([
  {
    key: '1',
    name: 'John Brown',
    age: 32,
    address: 'New York No.1 Lake Park'
  },
  {
    key: '2',
    name: 'Jim Green',
    age: 42,
    address: 'London No.1 Lake Park'
  },
  {
    key: '3',
    name: 'Joe Black',
    age: 32,
    address: 'Sidney No.12 Lake Park'
  },
  {
    key: '4',
    name: 'Jim Red',
    age: 32,
    address: 'London No.102 Lake Park'
  }
])
function onSortChange(column: TableColumn, currentDataSource: any[]) {
  console.log('sort column', column)
  console.log('sort currentDataSource', currentDataSource)
}
</script>
<template>
  <Flex vertical>
    <Space align="center"> bordered: <Switch v-model="sortBordered" /> </Space>
    <Table :columns="columnsSort" :data-source="dataSourceSort" :bordered="sortBordered" @sortChange="onSortChange" />
  </Flex>
</template>

可选择

可通过 rowSelection 属性来自定义选择功能


清空
Selected 1 items
NameAgeAddress
Edrward 032London, Park Lane no. 0
Edrward 132London, Park Lane no. 1
Edrward 232London, Park Lane no. 2
Edrward 332London, Park Lane no. 3
Edrward 432London, Park Lane no. 4
Edrward 532London, Park Lane no. 5
Edrward 632London, Park Lane no. 6
Edrward 732London, Park Lane no. 7
Edrward 832London, Park Lane no. 8
Edrward 932London, Park Lane no. 9
1 2345•••10
10 条/页
Show Code
vue
<script setup lang="ts">
import { ref, reactive, watchEffect } from 'vue'
import type { TableColumn, TableSelection } from 'vue-amazing-ui'
const selectionBordered = ref<boolean>(true)
const columnsSelection = reactive<TableColumn[]>([
  {
    title: 'Name',
    dataIndex: 'name'
  },
  {
    title: 'Age',
    dataIndex: 'age'
  },
  {
    title: 'Address',
    dataIndex: 'address'
  }
])
const data: any[] = []
for (let i = 0; i < 100; i++) {
  data.push({
    key: i.toString(),
    name: `Edrward ${i}`,
    age: 32,
    address: `London, Park Lane no. ${i}`
  })
}
const dataSourceSelection = ref(data)
const selectionTypeOptions = [
  {
    label: 'Checkbox',
    value: 'checkbox'
  },
  {
    label: 'Radio',
    value: 'radio'
  }
]
const rowSelection = reactive<TableSelection>({
  columnTitle: undefined,
  columnWidth: 100,
  fixed: true,
  hideSelectAll: false,
  type: 'checkbox',
  selectedRowKeys: ['3'],
  onChange: (selectedRowKeys: string[], selectedRows: any[]) => {
    console.log('onChange')
    console.log('selectedRowKeys', selectedRowKeys)
    console.log('selectedRows', selectedRows)
    rowSelection.selectedRowKeys = selectedRowKeys
  },
  onSelect: (record: any, selected: boolean, selectedRows: any[], selectedRowKeys: string[]) => {
    console.log('onSelect')
    console.log('record', record)
    console.log('selected', selected)
    console.log('selectedRows', selectedRows)
    console.log('selectedRowKeys', selectedRowKeys)
  },
  onSelectAll: (
    selected: boolean,
    selectedRows: any[],
    changeRows: any[],
    selectedRowKeys: string[],
    changeRowKeys: string[]
  ) => {
    console.log('onSelectAll')
    console.log('selected', selected)
    console.log('selectedRows', selectedRows)
    console.log('changeRows', changeRows)
    console.log('selectedRowKeys', selectedRowKeys)
    console.log('changeRowKeys', changeRowKeys)
  },
  getSelectionProps: (record: any) => ({
    disabled: record.key === '5',
    name: record.name
  })
})
const clear = () => {
  rowSelection.selectedRowKeys = []
}
watchEffect(() => {
  console.log('rowSelection.selectedRowKeys', rowSelection.selectedRowKeys)
})
</script>
<template>
  <Flex vertical>
    <Row :gutter="[24, 12]">
      <Col :span="6">
        <Space gap="small" vertical> bordered: <Switch v-model="selectionBordered" /> </Space>
      </Col>
      <Col :span="6">
        <Flex gap="small" vertical>
          columnTitle: <Input v-model:value="rowSelection.columnTitle" placeholder="columnTitle" />
        </Flex>
      </Col>
      <Col :span="6">
        <Flex gap="small" vertical>
          columnWidth: <Slider v-model:value="rowSelection.columnWidth" :min="32" :max="120" />
        </Flex>
      </Col>
      <Col :span="6">
        <Space gap="small" vertical> fixed: <Switch v-model="rowSelection.fixed" /> </Space>
      </Col>
      <Col :span="6">
        <Space gap="small" vertical> hideSelectAll: <Switch v-model="rowSelection.hideSelectAll" /> </Space>
      </Col>
      <Col :span="6">
        <Space gap="small" vertical>
          type:
          <Radio :options="selectionTypeOptions" v-model:value="rowSelection.type" button button-style="solid" />
        </Space>
      </Col>
    </Row>
    <Space>
      <Button @click="clear">清空</Button>
    </Space>
    <Table
      :columns="columnsSelection"
      :data-source="dataSourceSelection"
      :row-selection="rowSelection"
      :bordered="selectionBordered"
      :scroll="{ x: 1500 }"
    >
      <template #header> Selected {{ rowSelection.selectedRowKeys?.length }} items </template>
      <template #bodyCell="{ column, text }">
        <template v-if="column.dataIndex === 'name'">
          <a>{{ text }}</a>
        </template>
      </template>
    </Table>
  </Flex>
</template>

APIs

Table

参数说明类型默认值
header表格标题string | slotundefined
footer表格尾部string | slotundefined
columns表格列的配置项Column[][]
dataSource表格数据数组object[][]
bordered是否展示外边框和列边框booleanfalse
rowClassName自定义行的类名string | ((record: any, rowIndex: number) => string)undefined
size表格大小'large' | 'middle' | small'large'
striped是否使用斑马条纹booleanfalse
loading是否加载中booleanfalse
spinPropsSpin 组件属性配置,参考 Spin Props,用于配置数据加载中object{}
emptyPropsEmpty 组件属性配置,参考 Empty Props,用于配置暂无数据object{}
ellipsisPropsEllipsis 组件属性配置,参考 Ellipsis Props,用于全局配置文本省略object{}
showSorterTooltip表头是否显示下一次排序的 tooltip 提示booleantrue
sortDirections支持的排序方式('ascend' | 'descend')[]['ascend', 'descend']
sortTooltipProps排序 Tooltip 组件属性配置,参考 Tooltip Props,用于全局配置排序弹出提示object{}
sticky是否设置粘性定位的表头和水平滚动条,设置之后表头和滚动条会跟随页面固定booleanfalse
showPagination是否显示分页booleantrue
paginationPagination 组件属性配置,参考 Pagination Props,用于配置分页功能object{}
rowSelection列表项是否可选择Selectionundefined
scroll表格是否可滚动,也可以指定滚动区域的宽、高ScrollOption | booleanundefined
scrollbarPropsScrollbar 组件属性配置,参考 Scrollbar Props,用于配置表格滚动条object{}
tableLayout表格布局方式,设为 fixed 表示内容不会影响列的布局,参考 table-layout 属性,固定表头/列或使用了 column.ellipsis 时,默认值为 fixed'auto' | 'fixed'undefined
showExpandColumn是否展示展开列booleanfalse
expandColumnTitle自定义展开列表头string | slotundefined
expandColumnWidth展开列的宽度string | number48
expandCell自定义展开按钮slotundefined
expandedRowRender自定义额外的展开行内容slotundefined
expandFixed是否固定展开列booleanfalse
expandedRowKeys
v-model
展开行的 key 数组,控制展开行的属性;需与 dataSource 数据中的 key 配合使用(string | number)[][]
expandRowByClick点击行是否展开booleanfalse

Column Type

名称说明类型默认值
title?列头显示文字stringundefined
align?列文本的对齐方式'left' | 'center' | 'right'undefined
width?列宽度,单位 pxstring | numberundefined
className?自定义列的类名stringundefined
colSpan?表头列合并,设置为 0 时,不渲染numberundefined
dataIndex列数据在数据项中对应的路径索引;数据展示列必传,操作列可忽略stringundefined
key?自定义列标识stringundefined
ellipsis?超过宽度是否自动省略booleanundefined
ellipsisProps?Ellipsis 组件属性配置,参考 Ellipsis Props,用于单独配置某列文本省略objectundefined
fixed?列是否固定'left' | 'right'undefined
slot?列插槽名称索引stringundefined
children?列表头分组的子节点Column[]undefined
showSorterTooltip?表头是否显示下一次排序的 tooltip 提示,较高优先级booleanundefined
sortTooltipProps?Tooltip 组件属性配置,参考 Tooltip Props,用于单独配置某列的排序弹出提示,较高优先级objectundefined
defaultSortOrder?默认排序顺序,建议只设置一列的默认排序;如果设置多列,则只有第一列默认排序生效'ascend' | 'descend'undefined
sortDirections?支持的排序方式('ascend' | 'descend')[]undefined
sorter?升序排序函数,参考 Array.sortcompareFunction,当列表头分组时,请将排序设置在叶子节点Functionundefined
customCell?设置单元格属性(record: any, rowIndex: number, column: Column) => object | undefinedundefined

Selection Type

名称说明类型默认值
columnTitle?自定义选择框标题string | VNodeundefined
columnWidth?列表选择框宽度string | numberundefined
fixed?复选框列是否固定在左边booleanundefined
hideSelectAll?是否隐藏全选复选框booleanundefined
type?复选框/单选框'checkbox' | 'radio'undefined
selectedRowKeys?选中项的 key 数组,需和 onChange 配合使用string[]undefined
onChange?选中项发生变化时的回调(selectedRowKeys: string[], selectedRows: any[]) => voidundefined
onSelect?点击除全选外某行选择框时的回调(record: any, selected: boolean, selectedRows: any[], selectedRowKeys: string[]) => voidundefined
onSelectAll?点击复选框全选时的回调(selected: boolean, selectedRows: any[], changeRows: any[], selectedRowKeys: string[], changeRowKeys: string[]) => voidundefined
getSelectionProps?选择框组件的属性配置(record: any, rowIndex: number) => objectundefined

ScrollOption Type

名称说明类型默认值
initialScrollPositionOnChange?当分页、排序变化后是否滚动到表格初始位置booleanundefined
x?设置横向滚动,也可用于指定滚动区域的宽,可以设置为像素值,百分比,true'max-content'string | number | trueundefined
y?设置纵向滚动,也可用于指定滚动区域的高,可以设置为像素值string | numberundefined

Slots

名称说明类型
header自定义表格标题v-slot:header
footer自定义表格尾部v-slot:footer
expandColumnTitle自定义展开列表头v-slot:expandColumnTitle
headerCell个性化头部单元格v-slot:headerCell="{ column, title }"
expandCell自定义展开按钮v-slot:expandCell="{ record, index, expanded }"
bodyCell个性化单元格v-slot:bodyCell="{ column, record, text, index }"
expandedRowRender自定义额外的展开行内容v-slot:expandedRowRender="{ record, index, expanded }"

Events

名称说明类型
expand点击展开图标时的回调(expanded: boolean, record: any) => void
expandedRowsChange展开的行变化时的回调(expandedRows: string[]) => void
sortChange排序变化时的回调(column: Column, currentDataSource: any[]) => void
change分页变化时的回调(pager: { page: number, pageSize: number }) => void

Released under the MIT License.