mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
docs(components): [virtualized-table] finishing leftovers (#7496)
- Finishing the documentation examples - Add APIs to the documentation - Fix some issue while updating the documentations
This commit is contained in:
@@ -2,7 +2,6 @@ import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { vpRoot } from '@element-plus/build-utils'
|
||||
import { languages } from '../utils/lang'
|
||||
import { features } from './features'
|
||||
|
||||
import type { HeadConfig } from 'vitepress'
|
||||
|
||||
@@ -59,13 +58,6 @@ export const head: HeadConfig[] = [
|
||||
content: '/browserconfig.xml',
|
||||
},
|
||||
],
|
||||
[
|
||||
'link',
|
||||
{
|
||||
rel: 'stylesheet',
|
||||
href: '//fonts.loli.net/css?family=Inter:300,400,500,600|Open+Sans:400,600;display=swap',
|
||||
},
|
||||
],
|
||||
[
|
||||
'script',
|
||||
{},
|
||||
@@ -84,7 +76,9 @@ export const head: HeadConfig[] = [
|
||||
],
|
||||
[
|
||||
'script',
|
||||
{},
|
||||
{
|
||||
async: 'true',
|
||||
},
|
||||
`window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
@@ -92,7 +86,9 @@ gtag('config', 'UA-175337989-1');`,
|
||||
],
|
||||
[
|
||||
'script',
|
||||
{},
|
||||
{
|
||||
async: 'true',
|
||||
},
|
||||
`(function(h,o,t,j,a,r){
|
||||
h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
|
||||
h._hjSettings={hjid:2894908,hjsv:6};
|
||||
@@ -102,11 +98,24 @@ gtag('config', 'UA-175337989-1');`,
|
||||
a.appendChild(r);
|
||||
})(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');`,
|
||||
],
|
||||
]
|
||||
if (features.theme) {
|
||||
head.push([
|
||||
[
|
||||
'script',
|
||||
{},
|
||||
fs.readFileSync(path.resolve(vpRoot, 'dark-mode.js'), 'utf-8'),
|
||||
])
|
||||
}
|
||||
{
|
||||
async: 'true',
|
||||
},
|
||||
`
|
||||
var resource = document.createElement('link');
|
||||
resource.setAttribute("rel", "stylesheet");
|
||||
resource.setAttribute("href","//fonts.loli.net/css?family=Inter:300,400,500,600|Open+Sans:400,600;display=swap");
|
||||
resource.setAttribute("type","text/css");
|
||||
var head = document.querySelector('head');
|
||||
head.appendChild(resource);
|
||||
`,
|
||||
],
|
||||
]
|
||||
|
||||
head.push([
|
||||
'script',
|
||||
{},
|
||||
fs.readFileSync(path.resolve(vpRoot, 'dark-mode.js'), 'utf-8'),
|
||||
])
|
||||
|
||||
@@ -194,6 +194,11 @@
|
||||
"link": "/table",
|
||||
"text": "Table"
|
||||
},
|
||||
{
|
||||
"link": "/table-v2",
|
||||
"text": "Virtualized Table",
|
||||
"promotion": "2.2.0"
|
||||
},
|
||||
{
|
||||
"link": "/tag",
|
||||
"text": "Tag"
|
||||
|
||||
@@ -237,6 +237,14 @@ form {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
details {
|
||||
summary {
|
||||
margin: 16px 0;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.el-popover.is-light.translation-popup {
|
||||
background-color: var(--bg-color) !important;
|
||||
border-color: var(--border-color);
|
||||
|
||||
@@ -3,7 +3,7 @@ title: Virtualized Table
|
||||
lang: en-US
|
||||
---
|
||||
|
||||
# Virtualized Table
|
||||
# Virtualized Table <el-tag round effect="plain">Beta</el-tag>
|
||||
|
||||
Along with the evolutionary web development, table component has always been the most popular component in our web apps especially for dashboards, data analysis. For [Table V1](./table.md), with even just 1000 records of data, it can be very annoying when using it, because the poor performance.
|
||||
|
||||
@@ -11,6 +11,9 @@ With Virtualized Table, you can render massive chunks of data in a blink of an e
|
||||
|
||||
:::tip
|
||||
|
||||
This component is **still under testing**, use at your own risk. if you found any bug or issue please report it at [GitHub](https://github.com/element-plus/element-plus/issues) for us to fix. Also there were some APIs which was not mentioned in this documentation, some of them were not
|
||||
fully developed yet, so that we are not mentioning them here.
|
||||
|
||||
**Even though** Virtualized Table is efficient, but when the data load is too big, your **network**, **memory size** can be the bottle neck of your app. So keep in mind that Virtualized Table is never the ultimate solution for everything, consider paginate your data, add filters etc.
|
||||
|
||||
:::
|
||||
@@ -99,6 +102,27 @@ table-v2/filter
|
||||
|
||||
:::
|
||||
|
||||
## Sortable
|
||||
|
||||
You can sort the table with sort state.
|
||||
|
||||
:::demo
|
||||
|
||||
table-v2/sort
|
||||
|
||||
:::
|
||||
|
||||
## Controlled Sort
|
||||
|
||||
You can define multiple sortable column when you need it. Keep in mind that if you define multiple sortable columns, the UI
|
||||
might seem strange to your users since the it is unclear which column is being sorted.
|
||||
|
||||
:::demo
|
||||
|
||||
table-v2/controlled-sort
|
||||
|
||||
:::
|
||||
|
||||
## Colspan
|
||||
|
||||
Virtualized table did not use built-in `table` element, so that `colspan` and `rowspan` is a little bit different than [TableV1](./table.md). With customized row renderer, we can still do that. In this case, you'll learn how to do that.
|
||||
@@ -129,3 +153,281 @@ We can combine rowspan and colspan together to meet your business goal!
|
||||
table-v2/spans
|
||||
|
||||
:::
|
||||
|
||||
## Tree data
|
||||
|
||||
Virtual Table can also render data like tree, you can expand/collapse the tree node by clicking the arrow icon.
|
||||
|
||||
:::demo
|
||||
|
||||
table-v2/tree-data
|
||||
|
||||
:::
|
||||
|
||||
## Dynamic height rows
|
||||
|
||||
Virtual Table can also render rows with dynamic height, when you have data without knowing how big the content it would be, you
|
||||
might want to use this feature for rendering a dynamic height row. You must pass down `estimated-row-height` to enable this
|
||||
feature, and the closer the estimated height is, the smoother the rendering will be.
|
||||
|
||||
:::tip
|
||||
|
||||
The height of each row is dynamically measured while rendering the rows, so that the UI **might be** bouncing if you are trying
|
||||
to render a large amount of data.
|
||||
|
||||
:::
|
||||
|
||||
:::demo
|
||||
|
||||
table-v2/dynamic-height
|
||||
|
||||
:::
|
||||
|
||||
## Detail view
|
||||
|
||||
With dynamic height rendering, we can use that to render detail view in the table.
|
||||
|
||||
:::demo
|
||||
|
||||
table-v2/detailed-view
|
||||
|
||||
:::
|
||||
|
||||
## Customized Footer
|
||||
|
||||
Rendering a customized footer when you want to show a concluding message or information.
|
||||
|
||||
:::demo
|
||||
|
||||
table-v2/footer
|
||||
|
||||
:::
|
||||
|
||||
## Customized Empty Renderer
|
||||
|
||||
Render customized empty element
|
||||
|
||||
:::demo
|
||||
|
||||
table-v2/empty
|
||||
|
||||
:::
|
||||
|
||||
## Overlay
|
||||
|
||||
Render an overlay above the table when you want to show a loading indicator or something else.
|
||||
|
||||
:::demo
|
||||
|
||||
table-v2/overlay
|
||||
|
||||
:::
|
||||
|
||||
## TableV2 Attributes
|
||||
|
||||
| Attribute | Description | Type | Default |
|
||||
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | --------- |
|
||||
| cache | Number of rows rendered in advance for boosting the performance | Number | 2 |
|
||||
| estimated-row-height | The estimated row height for rendering dynamic height rows | Number | - |
|
||||
| header-class | Customized class name passed to header wrapper | String/Function\<[HeaderClassGetter](#typings)\> | - |
|
||||
| header-props | Customized props name passed to header component | Object/Function\<[HeaderPropsGetter](#typings)\> | - |
|
||||
| header-cell-props | Customized props name passed to header cell component | Object/Function\<[HeaderCellPropsGetter](#typings)\> | - |
|
||||
| header-height | The height of entire header, when it's array, it will render as many header rows as the given array's length | Number/Array\<Number\> | 50 |
|
||||
| footer-height | The height of the footer element, when presented, it will be part of the calculation of the table's height. | Number | 0 |
|
||||
| row-class | Customized class name passed to row wrapper | String/Function\<[RowClassGetter](#typings)\> | - |
|
||||
| row-key | The key of each row, if not provided, it will be the index of the row | String/Symbol/Number | id |
|
||||
| row-props | Customized props name passed to row component | Object/Function\<[RowPropsGetter](#typings)\> | - |
|
||||
| row-height | The height of each row, used for calculating the total height of the table | Number | 50 |
|
||||
| columns | An array of column definitions. | Array\<[Column](#column-attribute)\> | - |
|
||||
| data | An array of data to be rendered in the table. | Array\<[Data](#typings)\> | [] |
|
||||
| data-getter | An method which helps customizing the how to fetch the data from the data source. | Function | - |
|
||||
| fixed-data | Data for rendering rows above the main content and below the header | Array\<[Data](#typings)\> | - |
|
||||
| expand-column-key | The column key indicates which row is expandable | String | - |
|
||||
| expanded-row-keys | An array of keys for expanded rows, can be used with `v-model` | Array\<[KeyType](#typings)\> | - |
|
||||
| default-expanded-row-keys | An array of keys for default expanded rows, **NON REACTIVE** | Array\<[KeyType](#typings)\> | - |
|
||||
| class | Class name for the the virtual table, will be applied to all three tables (left, right, main) | String/Array/Object | - |
|
||||
| fixed | Flag indicates the table column's width is a fixed or flexible. | Boolean | false |
|
||||
| width \* | Width for the table, required | Number | - |
|
||||
| height \* | Height for the table, required | Number | - |
|
||||
| max-height | Maximum height for the table | Number | - |
|
||||
| h-scrollbar-size | Indicates the horizontal scrollbar's size for the table, used to prevent the horizontal and vertical scrollbar to collapse | Number | 6 |
|
||||
| v-scrollbar-size | Indicates the horizontal scrollbar's size for the table, used to prevent the horizontal and vertical scrollbar to collapse | Number | 6 |
|
||||
| scrollbar-always-on | If true, the scrollbar will always be shown instead of when mouse is placed above the table | Boolean | false |
|
||||
| sort-by | Sort indicator | Object\<[SortBy](#typings)\> | {} |
|
||||
| sort-state | Multiple sort indicator | Object\<[SortState](#typings)\> | undefined |
|
||||
|
||||
## TableV2 Slots
|
||||
|
||||
| Name | Params |
|
||||
| ----------- | ------------------------------- |
|
||||
| cell | [CellSlotProps](#typings) |
|
||||
| header | [HeaderSlotProps](#typings) |
|
||||
| header-cell | [HeaderCellSlotProps](#typings) |
|
||||
| row | [RowSlotProps](#typings) |
|
||||
| footer | - |
|
||||
| empty | - |
|
||||
| overlay | - |
|
||||
|
||||
## Table Methods
|
||||
|
||||
| Event Name | Description | Parameters |
|
||||
| -------------------- | --------------------------------------------- | ---------------------------------------- |
|
||||
| column-sort | Invoked when column sorted | Object\<ColumnSortParam\> |
|
||||
| expanded-rows-change | Invoked when expanded rows changed | `Array<KeyType>` |
|
||||
| end-reached | Invoked when the end of the table is reached | - |
|
||||
| scroll | Invoked after scrolled | Object\<[ScrollParams](#typings)\> |
|
||||
| rows-rendered | Invoked when rows are rendered | Object\<[RowsRenderedParams](#typings)\> |
|
||||
| row-event-handlers | A collection of handlers attached to each row | Object\<[RowEventHandlers](#typings)\> |
|
||||
|
||||
:::tip
|
||||
|
||||
Note that these are `JavaScript` Objects, so that you **CANNOT USE** kebab-case for these attributes
|
||||
|
||||
:::
|
||||
|
||||
## Column Attribute
|
||||
|
||||
| Attribute | Description | Type | Default |
|
||||
| -------------- | ------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
|
||||
| align | Alignment of the table cell content | [Alignment](https://github.com/element-plus/element-plus/blob/b92b22932758f0ddea98810ae248f6ca62f77e25/packages/components/table-v2/src/constants.ts#L6) | left |
|
||||
| class | Class name for the column | String | - |
|
||||
| fixed | Fixed direction of the column | Boolean/[FixedDir](https://github.com/element-plus/element-plus/blob/b92b22932758f0ddea98810ae248f6ca62f77e25/packages/components/table-v2/src/constants.ts#L11) | false |
|
||||
| flexGrow | CSSProperties flex grow, Only useful when not this is not a fixed table | Number | 0 |
|
||||
| flexShrink | CSSProperties flex shrink, Only useful when not this is not a fixed table | Number | 1 |
|
||||
| headerClass | Used for customizing header column class | String | - |
|
||||
| hidden | Whether the column is invisible | Boolean | - |
|
||||
| style | Customized style for column cell, will be merged with grid cell | CSSProperties | - |
|
||||
| sortable | Indicates whether the column is sortable | Boolean | - |
|
||||
| title | The default text rendered in header cell | String | - |
|
||||
| maxWidth | Maximum width for the column | String | - |
|
||||
| minWidth | Minimum width for the column | String | - |
|
||||
| width \* | Width for the column **Required** | Number | - |
|
||||
| cellRenderer | Customized Cell renderer | VueComponent/(props: [CellRenderProps](#renderer-typings)) => VNode | - |
|
||||
| headerRenderer | Customized Header renderer | VueComponent/(props: [HeaderRenderProps](#renderer-typings)) => VNode | - |
|
||||
|
||||
## Typings
|
||||
|
||||
<details>
|
||||
<summary>Show Type Declarations</summary>
|
||||
|
||||
```ts
|
||||
type HeaderClassGetter = (param: {
|
||||
columns: Column<any>[]
|
||||
headerIndex: number
|
||||
}) => string
|
||||
|
||||
type HeaderPropsGetter = (param: {
|
||||
columns: Column<any>[]
|
||||
headerIndex: number
|
||||
}) => Record<string, any>
|
||||
|
||||
type HeaderCellPropsGetter = (param: {
|
||||
columns: Column<any>[]
|
||||
column: Column<any>
|
||||
columnIndex: number
|
||||
headerIndex: number
|
||||
style: CSSProperties
|
||||
}) => Record<string, any>
|
||||
|
||||
type RowClassGetter = (param: {
|
||||
columns: Column<any>[]
|
||||
rowData: any
|
||||
rowIndex: number
|
||||
}) => string
|
||||
|
||||
type RowPropsGetter = (param: {
|
||||
columns: Column<any>[]
|
||||
rowData: any
|
||||
rowIndex: number
|
||||
}) => Record<string, any>
|
||||
|
||||
type CellRenderProps<T> = {
|
||||
cellData: T
|
||||
column: Column<T>
|
||||
columns: Column<T>[]
|
||||
columnIndex: number
|
||||
rowData: any
|
||||
rowIndex: number
|
||||
}
|
||||
|
||||
type HeaderRenderProps<T> = {
|
||||
column: Column<T>
|
||||
columns: Column<T>[]
|
||||
columnIndex: number
|
||||
headerIndex: number
|
||||
}
|
||||
|
||||
type ScrollParams = {
|
||||
xAxisScrollDir: 'forward' | 'backward'
|
||||
scrollLeft: number
|
||||
yAxisScrollDir: 'forward' | 'backward'
|
||||
scrollTop: number
|
||||
}
|
||||
|
||||
type CellSlotProps<T> = {
|
||||
column: Column<T>
|
||||
columns: Column<T>[]
|
||||
columnIndex: number
|
||||
depth: number
|
||||
style: CSSProperties
|
||||
rowData: any
|
||||
rowIndex: number
|
||||
isScrolling: boolean
|
||||
expandIconProps?:
|
||||
| {
|
||||
rowData: any
|
||||
rowIndex: number
|
||||
onExpand: (expand: boolean) => void
|
||||
}
|
||||
| undefined
|
||||
}
|
||||
|
||||
type HeaderSlotProps = {
|
||||
cells: VNode[]
|
||||
columns: Column<any>[]
|
||||
headerIndex: number
|
||||
}
|
||||
|
||||
type HeaderCellSlotProps = {
|
||||
class: string
|
||||
columns: Column<any>[]
|
||||
column: Column<any>
|
||||
columnIndex: number
|
||||
headerIndex: number
|
||||
style: CSSProperties
|
||||
headerCellProps?: any
|
||||
sortBy: SortBy
|
||||
sortState?: SortState | undefined
|
||||
onColumnSorted: (e: MouseEvent) => void
|
||||
}
|
||||
|
||||
type RowSlotProps = {
|
||||
columnIndex: number
|
||||
rowIndex: number
|
||||
data: any
|
||||
key: number | string
|
||||
isScrolling?: boolean | undefined
|
||||
style: CSSProperties
|
||||
}
|
||||
|
||||
type Data = {
|
||||
[key: KeyType]: any
|
||||
children?: Array<any>
|
||||
}
|
||||
|
||||
type FixedData = Data
|
||||
|
||||
type KeyType = string | number | symbol
|
||||
|
||||
type ColumnSortParam<T> = { column: Column<T>; key: KeyType; order: SortOrder }
|
||||
|
||||
enum SortOrder {
|
||||
ASC = 'asc',
|
||||
DESC = 'desc',
|
||||
}
|
||||
|
||||
type SortBy = { key: KeyType; Order: SortOrder }
|
||||
type SortState = Record<KeyType, SortOrder>
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
@@ -1,11 +1,41 @@
|
||||
<template>
|
||||
<table-v2 :columns="columns" :data="data" :width="700" :height="400" fixed />
|
||||
<el-table-v2
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:width="700"
|
||||
:height="400"
|
||||
fixed
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import TableV2 from '@element-plus/components/table-v2/src/table-v2'
|
||||
import { generateColumns, generateData } from './utils'
|
||||
const generateColumns = (length = 10, prefix = 'column-', props?: any) =>
|
||||
Array.from({ length }).map((_, columnIndex) => ({
|
||||
...props,
|
||||
key: `${prefix}${columnIndex}`,
|
||||
dataKey: `${prefix}${columnIndex}`,
|
||||
title: `Column ${columnIndex}`,
|
||||
width: 150,
|
||||
}))
|
||||
|
||||
const generateData = (
|
||||
columns: ReturnType<typeof generateColumns>,
|
||||
length = 200,
|
||||
prefix = 'row-'
|
||||
) =>
|
||||
Array.from({ length }).map((_, rowIndex) => {
|
||||
return columns.reduce(
|
||||
(rowData, column, columnIndex) => {
|
||||
rowData[column.dataKey] = `Row ${rowIndex} - Col ${columnIndex}`
|
||||
return rowData
|
||||
},
|
||||
{
|
||||
id: `${prefix}${rowIndex}`,
|
||||
parentId: null,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
const columns = generateColumns(10)
|
||||
const data = generateData(columns, 1000)
|
||||
const data = generateData(columns, 200)
|
||||
</script>
|
||||
|
||||
@@ -1,15 +1,26 @@
|
||||
<template>
|
||||
<table-v2 :columns="columns" :data="data" :width="700" :height="400" fixed />
|
||||
<el-table-v2
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:width="700"
|
||||
:height="400"
|
||||
fixed
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="tsx" setup>
|
||||
import { ref } from 'vue'
|
||||
import dayjs from 'dayjs'
|
||||
import {
|
||||
ElButton,
|
||||
ElIcon,
|
||||
ElTag,
|
||||
ElTooltip,
|
||||
TableV2FixedDir,
|
||||
} from 'element-plus'
|
||||
import { Timer } from '@element-plus/icons-vue'
|
||||
import { ElButton, ElIcon, ElTag, ElTooltip } from '@element-plus/components'
|
||||
import { FixedDir, TableV2 } from '@element-plus/components/table-v2'
|
||||
|
||||
import type { Column } from '@element-plus/components/table-v2'
|
||||
import type { Column } from 'element-plus'
|
||||
|
||||
let id = 0
|
||||
|
||||
@@ -25,7 +36,7 @@ const columns: Column<any>[] = [
|
||||
title: 'Date',
|
||||
dataKey: 'date',
|
||||
width: 150,
|
||||
fixed: FixedDir.LEFT,
|
||||
fixed: TableV2FixedDir.LEFT,
|
||||
cellRenderer: ({ cellData: date }) => (
|
||||
<ElTooltip content={dayjs(date).format('YYYY/MM/DD')}>
|
||||
{
|
||||
@@ -63,5 +74,5 @@ const columns: Column<any>[] = [
|
||||
},
|
||||
]
|
||||
|
||||
const data = ref(Array.from({ length: 5000 }).map(dataGenerator))
|
||||
const data = ref(Array.from({ length: 200 }).map(dataGenerator))
|
||||
</script>
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
<template>
|
||||
<table-v2 fixed :columns="columns" :data="data" :width="700" :height="400">
|
||||
<el-table-v2 fixed :columns="columns" :data="data" :width="700" :height="400">
|
||||
<template #row="props">
|
||||
<Row v-bind="props" />
|
||||
</template>
|
||||
</table-v2>
|
||||
</el-table-v2>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { cloneVNode } from 'vue'
|
||||
import TableV2 from '@element-plus/components/table-v2/src/table-v2'
|
||||
|
||||
const generateColumns = (length = 10, prefix = 'column-', props?: any) =>
|
||||
Array.from({ length }).map((_, columnIndex) => ({
|
||||
|
||||
60
docs/examples/table-v2/controlled-sort.vue
Normal file
60
docs/examples/table-v2/controlled-sort.vue
Normal file
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<el-table-v2
|
||||
v-model:sort-state="sortState"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:width="700"
|
||||
:height="400"
|
||||
fixed
|
||||
@column-sort="onSort"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { TableV2SortOrder } from 'element-plus'
|
||||
import type { SortBy, SortState } from 'element-plus'
|
||||
|
||||
const generateColumns = (length = 10, prefix = 'column-', props?: any) =>
|
||||
Array.from({ length }).map((_, columnIndex) => ({
|
||||
...props,
|
||||
key: `${prefix}${columnIndex}`,
|
||||
dataKey: `${prefix}${columnIndex}`,
|
||||
title: `Column ${columnIndex}`,
|
||||
width: 150,
|
||||
}))
|
||||
|
||||
const generateData = (
|
||||
columns: ReturnType<typeof generateColumns>,
|
||||
length = 200,
|
||||
prefix = 'row-'
|
||||
) =>
|
||||
Array.from({ length }).map((_, rowIndex) => {
|
||||
return columns.reduce(
|
||||
(rowData, column, columnIndex) => {
|
||||
rowData[column.dataKey] = `Row ${rowIndex} - Col ${columnIndex}`
|
||||
return rowData
|
||||
},
|
||||
{
|
||||
id: `${prefix}${rowIndex}`,
|
||||
parentId: null,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
const columns = generateColumns(10)
|
||||
const data = ref(generateData(columns, 200))
|
||||
|
||||
columns[0].sortable = true
|
||||
columns[1].sortable = true
|
||||
|
||||
const sortState = ref<SortState>({
|
||||
'column-0': TableV2SortOrder.DESC,
|
||||
'column-1': TableV2SortOrder.ASC,
|
||||
})
|
||||
|
||||
const onSort = ({ key, order }: SortBy) => {
|
||||
sortState.value[key] = order
|
||||
data.value = data.value.reverse()
|
||||
}
|
||||
</script>
|
||||
88
docs/examples/table-v2/detailed-view.vue
Normal file
88
docs/examples/table-v2/detailed-view.vue
Normal file
@@ -0,0 +1,88 @@
|
||||
<template>
|
||||
<el-table-v2
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:estimated-row-height="50"
|
||||
:expand-column-key="columns[0].key"
|
||||
:width="700"
|
||||
:height="400"
|
||||
>
|
||||
<template #row="props">
|
||||
<Row v-bind="props" />
|
||||
</template>
|
||||
</el-table-v2>
|
||||
</template>
|
||||
|
||||
<script lang="tsx" setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const detailedText = `Velit sed aspernatur tempora. Natus consequatur officiis dicta vel assumenda.
|
||||
Itaque est temporibus minus quis. Ipsum commodiab porro vel voluptas illum.
|
||||
Qui quam nulla et dolore autem itaque est.
|
||||
Id consequatur ipsum ea fuga et odit eligendi impedit.
|
||||
Maiores officiis occaecati et magnam et sapiente est velit sunt.
|
||||
Non et tempore temporibus. Excepturi et quos. Minus distinctio aut.
|
||||
Voluptatem ea excepturi omnis vel. Non aperiam sit sed laboriosam eaque omnis deleniti.
|
||||
Est molestiae omnis non et nulla repudiandae fuga sit.`
|
||||
|
||||
const generateColumns = (length = 10, prefix = 'column-', props?: any) =>
|
||||
Array.from({ length }).map((_, columnIndex) => ({
|
||||
...props,
|
||||
key: `${prefix}${columnIndex}`,
|
||||
dataKey: `${prefix}${columnIndex}`,
|
||||
title: `Column ${columnIndex}`,
|
||||
width: 150,
|
||||
}))
|
||||
|
||||
const generateData = (
|
||||
columns: ReturnType<typeof generateColumns>,
|
||||
length = 200,
|
||||
prefix = 'row-'
|
||||
) =>
|
||||
Array.from({ length }).map((_, rowIndex) => {
|
||||
return columns.reduce(
|
||||
(rowData, column, columnIndex) => {
|
||||
rowData[column.dataKey] = `Row ${rowIndex} - Col ${columnIndex}`
|
||||
return rowData
|
||||
},
|
||||
{
|
||||
id: `${prefix}${rowIndex}`,
|
||||
parentId: null,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
const columns = generateColumns(10)
|
||||
const data = ref(
|
||||
generateData(columns, 200).map((data) => {
|
||||
data.children = [
|
||||
{
|
||||
id: `${data.id}-detail-content`,
|
||||
detail: detailedText,
|
||||
},
|
||||
]
|
||||
return data
|
||||
})
|
||||
)
|
||||
|
||||
const Row = ({ cells, rowData }) => {
|
||||
if (rowData.detail) return <div class="p-6">{rowData.detail}</div>
|
||||
return cells
|
||||
}
|
||||
|
||||
Row.inheritAttrs = false
|
||||
|
||||
console.log(data)
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.el-table-v2__row-depth-0 {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.el-table-v2__cell-text {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
99
docs/examples/table-v2/dynamic-height.vue
Normal file
99
docs/examples/table-v2/dynamic-height.vue
Normal file
@@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<el-table-v2
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:sort-by="sort"
|
||||
:estimated-row-height="40"
|
||||
:width="700"
|
||||
:height="400"
|
||||
fixed
|
||||
@column-sort="onColumnSort"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="tsx" setup>
|
||||
import { ref } from 'vue'
|
||||
import {
|
||||
ElButton,
|
||||
ElTag,
|
||||
TableV2FixedDir,
|
||||
TableV2SortOrder,
|
||||
} from 'element-plus'
|
||||
|
||||
import type { Column, SortBy } from '@element-plus/components/table-v2'
|
||||
|
||||
const longText =
|
||||
'Quaerat ipsam necessitatibus eum quibusdam est id voluptatem cumque mollitia.'
|
||||
const midText = 'Corrupti doloremque a quos vero delectus consequatur.'
|
||||
const shortText = 'Eius optio fugiat.'
|
||||
|
||||
const textList = [shortText, midText, longText]
|
||||
|
||||
// generate random number in range 0 to 2
|
||||
|
||||
let id = 0
|
||||
|
||||
const dataGenerator = () => ({
|
||||
id: `random:${++id}`,
|
||||
name: 'Tom',
|
||||
date: '2016-05-03',
|
||||
description: textList[Math.floor(Math.random() * 3)],
|
||||
})
|
||||
|
||||
const columns: Column<any>[] = [
|
||||
{
|
||||
key: 'id',
|
||||
title: 'Id',
|
||||
dataKey: 'id',
|
||||
width: 150,
|
||||
sortable: true,
|
||||
fixed: TableV2FixedDir.LEFT,
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
title: 'Name',
|
||||
dataKey: 'name',
|
||||
width: 150,
|
||||
align: 'center',
|
||||
cellRenderer: ({ cellData: name }) => <ElTag>{name}</ElTag>,
|
||||
},
|
||||
{
|
||||
key: 'description',
|
||||
title: 'Description',
|
||||
dataKey: 'description',
|
||||
width: 150,
|
||||
cellRenderer: ({ cellData: description }) => (
|
||||
<div style="padding: 10px 0;">{description}</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'operations',
|
||||
title: 'Operations',
|
||||
cellRenderer: () => (
|
||||
<>
|
||||
<ElButton size="small">Edit</ElButton>
|
||||
<ElButton size="small" type="danger">
|
||||
Delete
|
||||
</ElButton>
|
||||
</>
|
||||
),
|
||||
width: 150,
|
||||
align: 'center',
|
||||
},
|
||||
]
|
||||
const data = ref(
|
||||
Array.from({ length: 200 })
|
||||
.map(dataGenerator)
|
||||
.sort((a, b) => (a.name > b.name ? 1 : -1))
|
||||
)
|
||||
|
||||
const sort = ref<SortBy>({ key: 'name', order: TableV2SortOrder.ASC })
|
||||
|
||||
const onColumnSort = (sortBy: SortBy) => {
|
||||
const order = sortBy.order === 'asc' ? 1 : -1
|
||||
const dataClone = [...data.value]
|
||||
dataClone.sort((a, b) => (a[sortBy.key] > b[sortBy.key] ? order : -order))
|
||||
sort.value = sortBy
|
||||
data.value = dataClone
|
||||
}
|
||||
</script>
|
||||
29
docs/examples/table-v2/empty.vue
Normal file
29
docs/examples/table-v2/empty.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<el-table-v2
|
||||
:columns="columns"
|
||||
:data="[]"
|
||||
:row-height="40"
|
||||
:width="700"
|
||||
:height="400"
|
||||
:footer-height="50"
|
||||
>
|
||||
<template #empty>
|
||||
<div class="flex items-center justify-center h-100%">
|
||||
<el-empty />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-v2>
|
||||
</template>
|
||||
|
||||
<script lang="tsx" setup>
|
||||
const generateColumns = (length = 10, prefix = 'column-', props?: any) =>
|
||||
Array.from({ length }).map((_, columnIndex) => ({
|
||||
...props,
|
||||
key: `${prefix}${columnIndex}`,
|
||||
dataKey: `${prefix}${columnIndex}`,
|
||||
title: `Column ${columnIndex}`,
|
||||
width: 150,
|
||||
}))
|
||||
|
||||
const columns = generateColumns(10)
|
||||
</script>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<table-v2
|
||||
<el-table-v2
|
||||
fixed
|
||||
:columns="fixedColumns"
|
||||
:data="data"
|
||||
@@ -9,11 +9,16 @@
|
||||
</template>
|
||||
<script lang="tsx" setup>
|
||||
import { ref } from 'vue'
|
||||
import { ElButton, ElCheckbox, ElIcon, ElPopover } from 'element-plus'
|
||||
import { FixedDir, TableV2 } from '@element-plus/components/table-v2'
|
||||
import {
|
||||
ElButton,
|
||||
ElCheckbox,
|
||||
ElIcon,
|
||||
ElPopover,
|
||||
TableV2FixedDir,
|
||||
} from 'element-plus'
|
||||
import { Filter } from '@element-plus/icons-vue'
|
||||
|
||||
import type { HeaderCellSlotProps } from '@element-plus/components/table-v2'
|
||||
import type { HeaderCellSlotProps } from 'element-plus'
|
||||
|
||||
const generateColumns = (length = 10, prefix = 'column-', props?: any) =>
|
||||
Array.from({ length }).map((_, columnIndex) => ({
|
||||
@@ -58,7 +63,7 @@ const onFilter = () => {
|
||||
|
||||
const onReset = () => {
|
||||
shouldFilter.value = false
|
||||
popoverRef.value.hide()
|
||||
onFilter()
|
||||
}
|
||||
|
||||
columns[0].headerCellRenderer = (props: HeaderCellSlotProps) => {
|
||||
@@ -74,7 +79,7 @@ columns[0].headerCellRenderer = (props: HeaderCellSlotProps) => {
|
||||
Filter Text
|
||||
</ElCheckbox>
|
||||
</div>
|
||||
<div class="table-v2__demo-filter">
|
||||
<div class="el-table-v2__demo-filter">
|
||||
<ElButton type="text" onClick={onFilter}>
|
||||
Confirm
|
||||
</ElButton>
|
||||
@@ -96,15 +101,15 @@ columns[0].headerCellRenderer = (props: HeaderCellSlotProps) => {
|
||||
}
|
||||
|
||||
const fixedColumns = columns.map((column, columnIndex) => {
|
||||
let fixed: FixedDir | undefined = undefined
|
||||
if (columnIndex < 2) fixed = FixedDir.LEFT
|
||||
if (columnIndex > 9) fixed = FixedDir.RIGHT
|
||||
let fixed: TableV2FixedDir | undefined = undefined
|
||||
if (columnIndex < 2) fixed = TableV2FixedDir.LEFT
|
||||
if (columnIndex > 9) fixed = TableV2FixedDir.RIGHT
|
||||
return { ...column, fixed, width: 100 }
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.table-v2__demo-filter {
|
||||
.el-table-v2__demo-filter {
|
||||
border-top: var(--el-border);
|
||||
margin: 12px -12px -12px;
|
||||
padding: 0 12px;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<table-v2
|
||||
<el-table-v2
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:sort-by="sortBy"
|
||||
@@ -12,9 +12,9 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { FixedDir, SortOrder, TableV2 } from '@element-plus/components/table-v2'
|
||||
import { TableV2FixedDir, TableV2SortOrder } from 'element-plus'
|
||||
|
||||
import type { SortBy } from '@element-plus/components/table-v2'
|
||||
import type { SortBy } from 'element-plus'
|
||||
|
||||
const generateColumns = (length = 10, prefix = 'column-', props?: any) =>
|
||||
Array.from({ length }).map((_, columnIndex) => ({
|
||||
@@ -47,14 +47,14 @@ const columns = generateColumns(10)
|
||||
let data = generateData(columns, 200)
|
||||
|
||||
columns[0].fixed = true
|
||||
columns[1].fixed = FixedDir.LEFT
|
||||
columns[9].fixed = FixedDir.RIGHT
|
||||
columns[1].fixed = TableV2FixedDir.LEFT
|
||||
columns[9].fixed = TableV2FixedDir.RIGHT
|
||||
|
||||
for (let i = 0; i < 3; i++) columns[i].sortable = true
|
||||
|
||||
const sortBy = ref<SortBy>({
|
||||
key: 'column-0',
|
||||
order: SortOrder.ASC,
|
||||
order: TableV2SortOrder.ASC,
|
||||
})
|
||||
|
||||
const onSort = (_sortBy: SortBy) => {
|
||||
|
||||
56
docs/examples/table-v2/footer.vue
Normal file
56
docs/examples/table-v2/footer.vue
Normal file
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<el-table-v2
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:row-height="40"
|
||||
:width="700"
|
||||
:height="400"
|
||||
:footer-height="50"
|
||||
fixed
|
||||
>
|
||||
<template #footer
|
||||
><div
|
||||
class="flex items-center"
|
||||
style="
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
background-color: var(--el-color-primary-light-7);
|
||||
"
|
||||
>
|
||||
Display a message in the footer
|
||||
</div>
|
||||
</template>
|
||||
</el-table-v2>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const generateColumns = (length = 10, prefix = 'column-', props?: any) =>
|
||||
Array.from({ length }).map((_, columnIndex) => ({
|
||||
...props,
|
||||
key: `${prefix}${columnIndex}`,
|
||||
dataKey: `${prefix}${columnIndex}`,
|
||||
title: `Column ${columnIndex}`,
|
||||
width: 150,
|
||||
}))
|
||||
|
||||
const generateData = (
|
||||
columns: ReturnType<typeof generateColumns>,
|
||||
length = 200,
|
||||
prefix = 'row-'
|
||||
) =>
|
||||
Array.from({ length }).map((_, rowIndex) => {
|
||||
return columns.reduce(
|
||||
(rowData, column, columnIndex) => {
|
||||
rowData[column.dataKey] = `Row ${rowIndex} - Col ${columnIndex}`
|
||||
return rowData
|
||||
},
|
||||
{
|
||||
id: `${prefix}${rowIndex}`,
|
||||
parentId: null,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
const columns = generateColumns(10)
|
||||
const data = generateData(columns, 200)
|
||||
</script>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<table-v2
|
||||
<el-table-v2
|
||||
fixed
|
||||
:columns="fixedColumns"
|
||||
:data="data"
|
||||
@@ -11,20 +11,16 @@
|
||||
<template #header="props">
|
||||
<customized-header v-bind="props" />
|
||||
</template>
|
||||
</table-v2>
|
||||
</el-table-v2>
|
||||
</template>
|
||||
<script lang="tsx" setup>
|
||||
import {
|
||||
FixedDir,
|
||||
TableV2,
|
||||
TableV2Placeholder,
|
||||
} from '@element-plus/components/table-v2'
|
||||
import { TableV2FixedDir, TableV2Placeholder } from 'element-plus'
|
||||
|
||||
import type { FunctionalComponent } from 'vue'
|
||||
import type {
|
||||
HeaderClassNameGetter,
|
||||
TableV2CustomizedHeaderSlotParam,
|
||||
} from '@element-plus/components/table-v2'
|
||||
} from 'element-plus'
|
||||
|
||||
const generateColumns = (length = 10, prefix = 'column-', props?: any) =>
|
||||
Array.from({ length }).map((_, columnIndex) => ({
|
||||
@@ -56,9 +52,9 @@ const columns = generateColumns(15)
|
||||
const data = generateData(columns, 200)
|
||||
|
||||
const fixedColumns = columns.map((column, columnIndex) => {
|
||||
let fixed: FixedDir | undefined = undefined
|
||||
if (columnIndex < 3) fixed = FixedDir.LEFT
|
||||
if (columnIndex > 12) fixed = FixedDir.RIGHT
|
||||
let fixed: TableV2FixedDir | undefined = undefined
|
||||
if (columnIndex < 3) fixed = TableV2FixedDir.LEFT
|
||||
if (columnIndex > 12) fixed = TableV2FixedDir.RIGHT
|
||||
return { ...column, fixed, width: 100 }
|
||||
})
|
||||
|
||||
@@ -112,11 +108,11 @@ const headerClass = ({
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.el-table-v2__header-row .custom-header-cell {
|
||||
.el-el-table-v2__header-row .custom-header-cell {
|
||||
border-right: 1px solid var(--el-border-color);
|
||||
}
|
||||
|
||||
.el-table-v2__header-row .custom-header-cell:last-child {
|
||||
.el-el-table-v2__header-row .custom-header-cell:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
|
||||
54
docs/examples/table-v2/overlay.vue
Normal file
54
docs/examples/table-v2/overlay.vue
Normal file
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<el-table-v2
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:row-height="40"
|
||||
:width="700"
|
||||
:height="400"
|
||||
>
|
||||
<template #overlay>
|
||||
<div
|
||||
class="el-loading-mask"
|
||||
style="display: flex; align-items: center; justify-content: center"
|
||||
>
|
||||
<el-icon class="is-loading" color="var(--el-color-primary)" :size="26">
|
||||
<loading-icon />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-v2>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Loading as LoadingIcon } from '@element-plus/icons-vue'
|
||||
|
||||
const generateColumns = (length = 10, prefix = 'column-', props?: any) =>
|
||||
Array.from({ length }).map((_, columnIndex) => ({
|
||||
...props,
|
||||
key: `${prefix}${columnIndex}`,
|
||||
dataKey: `${prefix}${columnIndex}`,
|
||||
title: `Column ${columnIndex}`,
|
||||
width: 150,
|
||||
}))
|
||||
|
||||
const generateData = (
|
||||
columns: ReturnType<typeof generateColumns>,
|
||||
length = 200,
|
||||
prefix = 'row-'
|
||||
) =>
|
||||
Array.from({ length }).map((_, rowIndex) => {
|
||||
return columns.reduce(
|
||||
(rowData, column, columnIndex) => {
|
||||
rowData[column.dataKey] = `Row ${rowIndex} - Col ${columnIndex}`
|
||||
return rowData
|
||||
},
|
||||
{
|
||||
id: `${prefix}${rowIndex}`,
|
||||
parentId: null,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
const columns = generateColumns(10)
|
||||
const data = generateData(columns, 200)
|
||||
</script>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<table-v2
|
||||
<el-table-v2
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:row-class="rowClass"
|
||||
@@ -12,14 +12,16 @@
|
||||
<script lang="tsx" setup>
|
||||
import { ref } from 'vue'
|
||||
import dayjs from 'dayjs'
|
||||
import {
|
||||
ElButton,
|
||||
ElIcon,
|
||||
ElTag,
|
||||
ElTooltip,
|
||||
TableV2FixedDir,
|
||||
} from 'element-plus'
|
||||
import { Timer } from '@element-plus/icons-vue'
|
||||
import { ElButton, ElIcon, ElTag, ElTooltip } from '@element-plus/components'
|
||||
import { FixedDir, TableV2 } from '@element-plus/components/table-v2'
|
||||
|
||||
import type {
|
||||
Column,
|
||||
RowClassNameGetter,
|
||||
} from '@element-plus/components/table-v2'
|
||||
import type { Column, RowClassNameGetter } from 'element-plus'
|
||||
|
||||
let id = 0
|
||||
|
||||
@@ -35,7 +37,7 @@ const columns: Column<any>[] = [
|
||||
title: 'Date',
|
||||
dataKey: 'date',
|
||||
width: 150,
|
||||
fixed: FixedDir.LEFT,
|
||||
fixed: TableV2FixedDir.LEFT,
|
||||
cellRenderer: ({ cellData: date }) => (
|
||||
<ElTooltip content={dayjs(date).format('YYYY/MM/DD')}>
|
||||
{
|
||||
@@ -73,7 +75,7 @@ const columns: Column<any>[] = [
|
||||
},
|
||||
]
|
||||
|
||||
const data = ref(Array.from({ length: 5000 }).map(dataGenerator))
|
||||
const data = ref(Array.from({ length: 200 }).map(dataGenerator))
|
||||
|
||||
const rowClass = ({ rowIndex }: Parameters<RowClassNameGetter<any>>[0]) => {
|
||||
if (rowIndex % 10 === 5) {
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
<template>
|
||||
<table-v2 fixed :columns="columns" :data="data" :width="700" :height="400">
|
||||
<el-table-v2 fixed :columns="columns" :data="data" :width="700" :height="400">
|
||||
<template #row="props">
|
||||
<Row v-bind="props" />
|
||||
</template>
|
||||
</table-v2>
|
||||
</el-table-v2>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { cloneVNode } from 'vue'
|
||||
import TableV2 from '@element-plus/components/table-v2/src/table-v2'
|
||||
|
||||
const generateColumns = (length = 10, prefix = 'column-', props?: any) =>
|
||||
Array.from({ length }).map((_, columnIndex) => ({
|
||||
|
||||
60
docs/examples/table-v2/sort.vue
Normal file
60
docs/examples/table-v2/sort.vue
Normal file
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<el-table-v2
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:sort-by="sortState"
|
||||
:width="700"
|
||||
:height="400"
|
||||
fixed
|
||||
@column-sort="onSort"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { TableV2SortOrder } from 'element-plus'
|
||||
import type { SortBy } from 'element-plus'
|
||||
|
||||
const generateColumns = (length = 10, prefix = 'column-', props?: any) =>
|
||||
Array.from({ length }).map((_, columnIndex) => ({
|
||||
...props,
|
||||
key: `${prefix}${columnIndex}`,
|
||||
dataKey: `${prefix}${columnIndex}`,
|
||||
title: `Column ${columnIndex}`,
|
||||
width: 150,
|
||||
}))
|
||||
|
||||
const generateData = (
|
||||
columns: ReturnType<typeof generateColumns>,
|
||||
length = 200,
|
||||
prefix = 'row-'
|
||||
) =>
|
||||
Array.from({ length }).map((_, rowIndex) => {
|
||||
return columns.reduce(
|
||||
(rowData, column, columnIndex) => {
|
||||
rowData[column.dataKey] = `Row ${rowIndex} - Col ${columnIndex}`
|
||||
return rowData
|
||||
},
|
||||
{
|
||||
id: `${prefix}${rowIndex}`,
|
||||
parentId: null,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
const columns = generateColumns(10)
|
||||
let data = generateData(columns, 200)
|
||||
|
||||
columns[0].sortable = true
|
||||
|
||||
const sortState = ref<SortBy>({
|
||||
key: 'column-0',
|
||||
order: TableV2SortOrder.ASC,
|
||||
})
|
||||
|
||||
const onSort = (sortBy: SortBy) => {
|
||||
console.log(sortBy)
|
||||
data = data.reverse()
|
||||
sortState.value = sortBy
|
||||
}
|
||||
</script>
|
||||
@@ -1,14 +1,13 @@
|
||||
<template>
|
||||
<table-v2 fixed :columns="columns" :data="data" :width="700" :height="400">
|
||||
<el-table-v2 fixed :columns="columns" :data="data" :width="700" :height="400">
|
||||
<template #row="props">
|
||||
<Row v-bind="props" />
|
||||
</template>
|
||||
</table-v2>
|
||||
</el-table-v2>
|
||||
</template>
|
||||
|
||||
<script lang="tsx" setup>
|
||||
import { cloneVNode } from 'vue'
|
||||
import { TableV2 } from '@element-plus/components/table-v2'
|
||||
|
||||
const generateColumns = (length = 10, prefix = 'column-', props?: any) =>
|
||||
Array.from({ length }).map((_, columnIndex) => ({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<table-v2
|
||||
<el-table-v2
|
||||
:columns="columns"
|
||||
:data="tableData"
|
||||
:fixed-data="fixedData"
|
||||
@@ -13,8 +13,33 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from 'vue'
|
||||
import { TableV2 } from '@element-plus/components/table-v2'
|
||||
import { generateColumns, generateData } from './utils'
|
||||
|
||||
const generateColumns = (length = 10, prefix = 'column-', props?: any) =>
|
||||
Array.from({ length }).map((_, columnIndex) => ({
|
||||
...props,
|
||||
key: `${prefix}${columnIndex}`,
|
||||
dataKey: `${prefix}${columnIndex}`,
|
||||
title: `Column ${columnIndex}`,
|
||||
width: 150,
|
||||
}))
|
||||
|
||||
const generateData = (
|
||||
columns: ReturnType<typeof generateColumns>,
|
||||
length = 200,
|
||||
prefix = 'row-'
|
||||
) =>
|
||||
Array.from({ length }).map((_, rowIndex) => {
|
||||
return columns.reduce(
|
||||
(rowData, column, columnIndex) => {
|
||||
rowData[column.dataKey] = `Row ${rowIndex} - Col ${columnIndex}`
|
||||
return rowData
|
||||
},
|
||||
{
|
||||
id: `${prefix}${rowIndex}`,
|
||||
parentId: null,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
const columns = generateColumns(10)
|
||||
const data = generateData(columns, 200)
|
||||
@@ -39,7 +64,7 @@ const onScroll = ({ scrollTop }) => {
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.el-table-v2__fixed-header-row {
|
||||
.el-el-table-v2__fixed-header-row {
|
||||
background-color: var(--el-color-primary-light-5);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
128
docs/examples/table-v2/tree-data.vue
Normal file
128
docs/examples/table-v2/tree-data.vue
Normal file
@@ -0,0 +1,128 @@
|
||||
<template>
|
||||
<el-table-v2
|
||||
v-model:expanded-row-keys="expandedRowKeys"
|
||||
:columns="columns"
|
||||
:data="treeData"
|
||||
:width="700"
|
||||
:expand-column-key="expandColumnKey"
|
||||
:height="400"
|
||||
fixed
|
||||
@row-expand="onRowExpanded"
|
||||
@expanded-rows-change="onExpandedRowsChange"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from 'vue'
|
||||
import { TableV2FixedDir } from 'element-plus'
|
||||
|
||||
import type { ExpandedRowsChangeHandler, RowExpandHandler } from 'element-plus'
|
||||
|
||||
const generateColumns = (length = 10, prefix = 'column-', props?: any) =>
|
||||
Array.from({ length }).map((_, columnIndex) => ({
|
||||
...props,
|
||||
key: `${prefix}${columnIndex}`,
|
||||
dataKey: `${prefix}${columnIndex}`,
|
||||
title: `Column ${columnIndex}`,
|
||||
width: 150,
|
||||
}))
|
||||
|
||||
const generateData = (
|
||||
columns: ReturnType<typeof generateColumns>,
|
||||
length = 200,
|
||||
prefix = 'row-'
|
||||
) =>
|
||||
Array.from({ length }).map((_, rowIndex) => {
|
||||
return columns.reduce(
|
||||
(rowData, column, columnIndex) => {
|
||||
rowData[column.dataKey] = `Row ${rowIndex} - Col ${columnIndex}`
|
||||
return rowData
|
||||
},
|
||||
{
|
||||
id: `${prefix}${rowIndex}`,
|
||||
parentId: null,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
const columns = generateColumns(10).map((column, columnIndex) => {
|
||||
let fixed!: TableV2FixedDir
|
||||
if (columnIndex < 2) fixed = TableV2FixedDir.LEFT
|
||||
if (columnIndex > 8) fixed = TableV2FixedDir.RIGHT
|
||||
return { ...column, fixed }
|
||||
})
|
||||
|
||||
const data = generateData(columns, 200)
|
||||
|
||||
const expandColumnKey = 'column-0'
|
||||
|
||||
// add some sub items
|
||||
for (let i = 0; i < 50; i++) {
|
||||
data.push(
|
||||
{
|
||||
...data[0],
|
||||
id: `${data[0].id}-sub-${i}`,
|
||||
parentId: data[0].id,
|
||||
[expandColumnKey]: `Sub ${i}`,
|
||||
},
|
||||
{
|
||||
...data[2],
|
||||
id: `${data[2].id}-sub-${i}`,
|
||||
parentId: data[2].id,
|
||||
[expandColumnKey]: `Sub ${i}`,
|
||||
},
|
||||
{
|
||||
...data[2],
|
||||
id: `${data[2].id}-sub-sub-${i}`,
|
||||
parentId: `${data[2].id}-sub-${i}`,
|
||||
[expandColumnKey]: `Sub-Sub ${i}`,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function unflatten(
|
||||
data: ReturnType<typeof generateData>,
|
||||
rootId = null,
|
||||
dataKey = 'id',
|
||||
parentKey = 'parentId'
|
||||
) {
|
||||
const tree: any[] = []
|
||||
const childrenMap = {}
|
||||
|
||||
for (const datum of data) {
|
||||
const item = { ...datum }
|
||||
const id = item[dataKey]
|
||||
const parentId = item[parentKey]
|
||||
|
||||
if (Array.isArray(item.children)) {
|
||||
childrenMap[id] = item.children.concat(childrenMap[id] || [])
|
||||
} else if (!childrenMap[id]) {
|
||||
childrenMap[id] = []
|
||||
}
|
||||
item.children = childrenMap[id]
|
||||
|
||||
if (parentId !== undefined && parentId !== rootId) {
|
||||
if (!childrenMap[parentId]) childrenMap[parentId] = []
|
||||
childrenMap[parentId].push(item)
|
||||
} else {
|
||||
tree.push(item)
|
||||
}
|
||||
}
|
||||
|
||||
return tree
|
||||
}
|
||||
|
||||
const treeData = computed(() => unflatten(data))
|
||||
|
||||
const expandedRowKeys = ref<string[]>([])
|
||||
|
||||
const onRowExpanded = ({ expanded }: Parameters<RowExpandHandler<any>>[0]) => {
|
||||
console.log('Expanded:', expanded)
|
||||
}
|
||||
|
||||
const onExpandedRowsChange = (
|
||||
expandedKeys: Parameters<ExpandedRowsChangeHandler>[0]
|
||||
) => {
|
||||
console.log(expandedKeys)
|
||||
}
|
||||
</script>
|
||||
@@ -1,26 +0,0 @@
|
||||
export const generateColumns = (length = 10, prefix = 'column-', props?: any) =>
|
||||
Array.from({ length }).map((_, columnIndex) => ({
|
||||
...props,
|
||||
key: `${prefix}${columnIndex}`,
|
||||
dataKey: `${prefix}${columnIndex}`,
|
||||
title: `Column ${columnIndex}`,
|
||||
width: 150,
|
||||
}))
|
||||
|
||||
export const generateData = (
|
||||
columns: ReturnType<typeof generateColumns>,
|
||||
length = 200,
|
||||
prefix = 'row-'
|
||||
) =>
|
||||
Array.from({ length }).map((_, rowIndex) => {
|
||||
return columns.reduce(
|
||||
(rowData, column, columnIndex) => {
|
||||
rowData[column.dataKey] = `Row ${rowIndex} - Col ${columnIndex}`
|
||||
return rowData
|
||||
},
|
||||
{
|
||||
id: `${prefix}${rowIndex}`,
|
||||
parentId: null,
|
||||
}
|
||||
)
|
||||
})
|
||||
@@ -53,6 +53,7 @@ export * from './space'
|
||||
export * from './steps'
|
||||
export * from './switch'
|
||||
export * from './table'
|
||||
export * from './table-v2'
|
||||
export * from './tabs'
|
||||
export * from './tag'
|
||||
export * from './time-picker'
|
||||
|
||||
@@ -1,13 +1,24 @@
|
||||
export { Alignment, FixedDir, SortOrder } from './src/constants'
|
||||
import { withInstall } from '@element-plus/utils'
|
||||
import TableV2 from './src/table-v2'
|
||||
|
||||
export {
|
||||
Alignment as TableV2Alignment,
|
||||
FixedDir as TableV2FixedDir,
|
||||
SortOrder as TableV2SortOrder,
|
||||
} from './src/constants'
|
||||
export { default as TableV2 } from './src/table-v2'
|
||||
export { placeholderSign as TableV2Placeholder } from './src/private'
|
||||
|
||||
export const ElTableV2 = withInstall(TableV2)
|
||||
|
||||
export type {
|
||||
Column,
|
||||
Columns,
|
||||
SortBy,
|
||||
SortState,
|
||||
TableV2CustomizedHeaderSlotParam,
|
||||
} from './src/types'
|
||||
export * from './src/table'
|
||||
export * from './src/row'
|
||||
|
||||
export type { HeaderCellSlotProps } from './src/renderers/header-cell'
|
||||
|
||||
@@ -11,5 +11,6 @@ const HeaderCell: FunctionalComponent<TableV2HeaderCell> = (props, { slots }) =>
|
||||
)
|
||||
|
||||
HeaderCell.displayName = 'ElTableV2HeaderCell'
|
||||
HeaderCell.inheritAttrs = false
|
||||
|
||||
export default HeaderCell
|
||||
|
||||
@@ -64,7 +64,7 @@ function useColumns(
|
||||
|
||||
return _columns.reduce<Record<Column<any>['key'], CSSProperties>>(
|
||||
(style, column) => {
|
||||
style[column.key] = calcColumnStyle(column, unref(fixed))
|
||||
style[column.key] = calcColumnStyle(column, unref(fixed), props.fixed)
|
||||
return style
|
||||
},
|
||||
{}
|
||||
|
||||
@@ -51,7 +51,7 @@ export const useRow = (
|
||||
const isDynamic = computed(() => isNumber(props.estimatedRowHeight))
|
||||
|
||||
function onRowsRendered(params: onRowRenderedParams) {
|
||||
props.onRowRendered?.(params)
|
||||
props.onRowsRendered?.(params)
|
||||
|
||||
if (params.rowCacheEnd > unref(lastRenderedRowIndex)) {
|
||||
lastRenderedRowIndex.value = params.rowCacheEnd
|
||||
|
||||
@@ -3,14 +3,21 @@ import type { AnyColumns } from '../types'
|
||||
|
||||
export const calcColumnStyle = (
|
||||
column: AnyColumns[number],
|
||||
fixedColumn: boolean
|
||||
fixedColumn: boolean,
|
||||
fixed: boolean
|
||||
): CSSProperties => {
|
||||
const flex = {
|
||||
flexGrow: 0,
|
||||
flexShrink: 0,
|
||||
...(fixed
|
||||
? {}
|
||||
: {
|
||||
flexGrow: column.flexGrow || 0,
|
||||
flexShrink: column.flexShrink || 1,
|
||||
}),
|
||||
}
|
||||
|
||||
if (column.fixed) {
|
||||
if (!fixed) {
|
||||
flex.flexShrink = 1
|
||||
}
|
||||
|
||||
|
||||
@@ -13,10 +13,7 @@ import type { UseTableReturn } from '../use-table'
|
||||
import type { TableV2Props } from '../table'
|
||||
|
||||
type CellRendererProps = TableV2RowCellRenderParam &
|
||||
Pick<
|
||||
TableV2Props,
|
||||
'cellProps' | 'expandColumnKey' | 'indentSize' | 'iconSize' | 'rowKey'
|
||||
> &
|
||||
Pick<TableV2Props, 'expandColumnKey' | 'indentSize' | 'iconSize' | 'rowKey'> &
|
||||
UnwrapNestedRefs<Pick<UseTableReturn, 'expandedRowKeys'>> & {
|
||||
ns: UseNamespaceReturn
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ const HeaderCellRenderer: FunctionalComponent<HeaderCellRendererProps> = (
|
||||
...tryCall(headerCellProps, props),
|
||||
onClick: column.sortable ? onColumnSorted : undefined,
|
||||
class: cellKls,
|
||||
cellStyle,
|
||||
style: cellStyle,
|
||||
['data-key']: column.key,
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import type {
|
||||
KeyType,
|
||||
RowCommonParams,
|
||||
SortBy,
|
||||
SortState,
|
||||
} from './types'
|
||||
|
||||
/**
|
||||
@@ -71,17 +72,12 @@ export type RowClassNameGetter<T> = (
|
||||
*/
|
||||
export type ColumnSortHandler<T> = (params: ColumnSortParams<T>) => void
|
||||
export type ColumnResizeHandler<T> = (column: Column<T>, width: number) => void
|
||||
export type ExpandedRowsChangeHandler = (expandedRowKeys: KeyType[]) => void
|
||||
|
||||
export const tableV2Props = buildProps({
|
||||
cache: tableV2GridProps.cache,
|
||||
estimatedRowHeight: tableV2RowProps.estimatedRowHeight,
|
||||
rowKey,
|
||||
/**
|
||||
* extra props deriver
|
||||
*/
|
||||
cellProps: {
|
||||
type: definePropType<any | ExtraCellPropGetter<any>>([Object, Function]),
|
||||
},
|
||||
// Header attributes
|
||||
headerClass: {
|
||||
type: definePropType<string | HeaderClassNameGetter<any>>([
|
||||
@@ -130,10 +126,6 @@ export const tableV2Props = buildProps({
|
||||
dataGetter: {
|
||||
type: definePropType<DataGetter<any>>(Function),
|
||||
},
|
||||
dataKey: {
|
||||
type: String,
|
||||
default: 'id',
|
||||
},
|
||||
fixedData: fixedDataType,
|
||||
/**
|
||||
* Expanded keys
|
||||
@@ -146,7 +138,7 @@ export const tableV2Props = buildProps({
|
||||
* Attributes
|
||||
*/
|
||||
class: classType,
|
||||
disabled: Boolean,
|
||||
// disabled: Boolean,
|
||||
fixed: Boolean,
|
||||
style: {
|
||||
type: definePropType<CSSProperties>(Object),
|
||||
@@ -176,7 +168,7 @@ export const tableV2Props = buildProps({
|
||||
},
|
||||
|
||||
sortState: {
|
||||
type: definePropType<Record<KeyType, SortOrder>>(Object),
|
||||
type: definePropType<SortState>(Object),
|
||||
default: undefined,
|
||||
},
|
||||
|
||||
@@ -186,13 +178,15 @@ export const tableV2Props = buildProps({
|
||||
onColumnSort: {
|
||||
type: definePropType<ColumnSortHandler<any>>(Function),
|
||||
},
|
||||
onExpandedRowsChange: Function,
|
||||
onExpandedRowsChange: {
|
||||
type: definePropType<ExpandedRowsChangeHandler>(Function),
|
||||
},
|
||||
onEndReached: {
|
||||
type: definePropType<(distance: number) => void>(Function),
|
||||
},
|
||||
onRowExpand: tableV2RowProps.onRowExpand,
|
||||
onScroll: tableV2GridProps.onScroll,
|
||||
onRowRendered: tableV2GridProps.onRowsRendered,
|
||||
onRowsRendered: tableV2GridProps.onRowsRendered,
|
||||
rowEventHandlers: tableV2RowProps.rowEventHandlers,
|
||||
} as const)
|
||||
|
||||
|
||||
@@ -61,19 +61,20 @@ export type HeaderCellRenderer<T> = (
|
||||
) => VNode
|
||||
|
||||
export type Column<T = any> = {
|
||||
key: KeyType
|
||||
/**
|
||||
* Attributes
|
||||
*/
|
||||
align?: Alignment
|
||||
class?: string | ClassNameGetter<T>
|
||||
dataKey: KeyType
|
||||
fixed?: true | FixedDirection
|
||||
flexGrow?: CSSProperties['flexGrow']
|
||||
flexShrink?: CSSProperties['flexShrink']
|
||||
title?: string
|
||||
hidden?: boolean
|
||||
headerClass?: HeaderClassGetter<T> | string
|
||||
maxWidth?: number
|
||||
minWidth?: number
|
||||
resizable?: boolean
|
||||
style?: CSSProperties
|
||||
sortable?: boolean
|
||||
width: number
|
||||
@@ -96,6 +97,10 @@ export type SortBy = {
|
||||
order: SortOrder
|
||||
}
|
||||
|
||||
export type SortState = {
|
||||
[key: KeyType]: SortOrder
|
||||
}
|
||||
|
||||
export type CustomizedCellsType = VNode<
|
||||
RendererNode,
|
||||
RendererElement,
|
||||
|
||||
2
packages/components/table-v2/style/css.ts
Normal file
2
packages/components/table-v2/style/css.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
import '@element-plus/components/base/style/css'
|
||||
import '@element-plus/theme-chalk/el-table-v2.css'
|
||||
2
packages/components/table-v2/style/index.ts
Normal file
2
packages/components/table-v2/style/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
import '@element-plus/components/base/style'
|
||||
import '@element-plus/theme-chalk/src/table-v2.scss'
|
||||
@@ -85,6 +85,7 @@ import { ElSpace } from '@element-plus/components/space'
|
||||
import { ElStep, ElSteps } from '@element-plus/components/steps'
|
||||
import { ElSwitch } from '@element-plus/components/switch'
|
||||
import { ElTable, ElTableColumn } from '@element-plus/components/table'
|
||||
import { ElTableV2 } from '@element-plus/components/table-v2'
|
||||
import { ElTabPane, ElTabs } from '@element-plus/components/tabs'
|
||||
import { ElTag } from '@element-plus/components/tag'
|
||||
import { ElTimePicker } from '@element-plus/components/time-picker'
|
||||
@@ -178,6 +179,7 @@ export default [
|
||||
ElSwitch,
|
||||
ElTable,
|
||||
ElTableColumn,
|
||||
ElTableV2,
|
||||
ElTabs,
|
||||
ElTabPane,
|
||||
ElTag,
|
||||
|
||||
@@ -142,6 +142,7 @@
|
||||
@include cell-alignment;
|
||||
height: 100%;
|
||||
user-select: none;
|
||||
overflow: hidden;
|
||||
background-color: getCssVar('table-header', 'bg-color');
|
||||
color: getCssVar('table-header', 'text-color');
|
||||
font-weight: bold;
|
||||
@@ -170,6 +171,8 @@
|
||||
}
|
||||
|
||||
@include e('row') {
|
||||
border-bottom: getCssVar('table', 'border');
|
||||
|
||||
@include center-flex;
|
||||
transition: background-color getCssVar('transition-duration', '');
|
||||
|
||||
@@ -180,7 +183,6 @@
|
||||
@include e('row-cell') {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
border-bottom: getCssVar('table', 'border');
|
||||
@include center-flex;
|
||||
@include cell-padding;
|
||||
@include cell-alignment;
|
||||
@@ -210,4 +212,11 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
@include when(dynamic) {
|
||||
@include e('row') {
|
||||
overflow: hidden;
|
||||
align-items: stretch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user