From 444b483a4df53fd6b83d53777d85817f68fd0f76 Mon Sep 17 00:00:00 2001 From: v_luopinluo <173308582@qq.com> Date: Fri, 23 Oct 2026 16:14:25 +0800 Subject: [PATCH] feat(table): add radio and checkbox --- packages/components/input/index.ts | 3 + packages/components/input/input.ts | 3 + packages/components/radio/index.ts | 3 + packages/components/radio/radio.ts | 3 + packages/components/table/README.en-US.md | 97 +++++ packages/components/table/README.md | 97 +++++ .../components/table/__test__/demo.test.js | 12 +- .../table/_example/custom-row-style/index.js | 55 +++ .../_example/custom-row-style/index.json | 6 + .../_example/custom-row-style/index.wxml | 8 + .../_example/custom-row-style/index.wxss | 5 + .../table/_example/loading/index.js | 42 ++ .../table/_example/loading/index.json | 6 + .../table/_example/loading/index.wxml | 23 ++ .../table/_example/loading/index.wxss | 9 + .../components/table/_example/select/index.js | 52 +++ .../table/_example/select/index.json | 6 + .../table/_example/select/index.wxml | 22 + .../table/_example/select/index.wxss | 9 + .../components/table/_example/sort/index.js | 53 +++ .../components/table/_example/sort/index.json | 6 + .../components/table/_example/sort/index.wxml | 9 + .../components/table/_example/sort/index.wxss | 1 + packages/components/table/_example/table.json | 6 +- packages/components/table/_example/table.wxml | 14 +- packages/components/table/base-table-props.ts | 17 + .../components/table/primary-table-props.ts | 115 ++++++ packages/components/table/table.json | 9 +- packages/components/table/table.less | 21 + packages/components/table/table.ts | 287 ++++++++++++- packages/components/table/table.wxml | 43 +- packages/components/table/type.ts | 389 +++++++++++++++++- 32 files changed, 1412 insertions(+), 19 deletions(-) create mode 100644 packages/components/input/index.ts create mode 100644 packages/components/radio/index.ts create mode 100644 packages/components/table/_example/custom-row-style/index.js create mode 100644 packages/components/table/_example/custom-row-style/index.json create mode 100644 packages/components/table/_example/custom-row-style/index.wxml create mode 100644 packages/components/table/_example/custom-row-style/index.wxss create mode 100644 packages/components/table/_example/loading/index.js create mode 100644 packages/components/table/_example/loading/index.json create mode 100644 packages/components/table/_example/loading/index.wxml create mode 100644 packages/components/table/_example/loading/index.wxss create mode 100644 packages/components/table/_example/select/index.js create mode 100644 packages/components/table/_example/select/index.json create mode 100644 packages/components/table/_example/select/index.wxml create mode 100644 packages/components/table/_example/select/index.wxss create mode 100644 packages/components/table/_example/sort/index.js create mode 100644 packages/components/table/_example/sort/index.json create mode 100644 packages/components/table/_example/sort/index.wxml create mode 100644 packages/components/table/_example/sort/index.wxss create mode 100644 packages/components/table/primary-table-props.ts diff --git a/packages/components/input/index.ts b/packages/components/input/index.ts new file mode 100644 index 0000000000..8f207a9568 --- /dev/null +++ b/packages/components/input/index.ts @@ -0,0 +1,3 @@ +export * from './props'; +export * from './type'; +export * from './input'; diff --git a/packages/components/input/input.ts b/packages/components/input/input.ts index 3fcd0cc238..6a9b5542ac 100644 --- a/packages/components/input/input.ts +++ b/packages/components/input/input.ts @@ -1,12 +1,15 @@ import { SuperComponent, wxComponent } from '../common/src/index'; import config from '../common/config'; import props from './props'; +import { TdInputProps } from './type'; import { getCharacterLength, calcIcon } from '../common/utils'; import { isDef } from '../common/validator'; const { prefix } = config; const name = `${prefix}-input`; +export type InputProps = TdInputProps; + @wxComponent() export default class Input extends SuperComponent { options = { diff --git a/packages/components/radio/index.ts b/packages/components/radio/index.ts new file mode 100644 index 0000000000..1b9c00a845 --- /dev/null +++ b/packages/components/radio/index.ts @@ -0,0 +1,3 @@ +export * from './props'; +export * from './type'; +export * from './radio'; diff --git a/packages/components/radio/radio.ts b/packages/components/radio/radio.ts index d4be4632f2..85f78f65a2 100644 --- a/packages/components/radio/radio.ts +++ b/packages/components/radio/radio.ts @@ -1,7 +1,10 @@ import config from '../common/config'; import { SuperComponent, wxComponent, RelationsOptions } from '../common/src/index'; +import { TdRadioProps } from './type'; import Props from './props'; +export type RadioProps = TdRadioProps; + const { prefix } = config; const name = `${prefix}-radio`; diff --git a/packages/components/table/README.en-US.md b/packages/components/table/README.en-US.md index d7c5d1448f..cddc5f1ad4 100644 --- a/packages/components/table/README.en-US.md +++ b/packages/components/table/README.en-US.md @@ -17,8 +17,12 @@ fixed-rows | Array | - | Typescript: `Array` | N footer-summary | String | - | footer summary content | N height | String / Number | - | table height | N loading | Boolean | undefined | loading state table | N +loading-mode | String | pull-refresh | Data Loading Mode。options: pull-refresh/pagination | N loading-props | Object | - | Typescript: `Partial`,[Loading API Documents](./loading?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N max-height | String / Number | - | table max height | N +pagination | Object | - | you can use all props of pagination component with paginationProps。Typescript: `PaginationProps` `interface PaginationProps { current?: number; defaultCurrent?: number; disabled?: boolean; foldedMaxPageBtn?: number; maxPageBtn?: number; pageEllipsisMode?: 'mid' \| 'both-ends'; pageSize?: number; defaultPageSize?: number; pageSizeOptions?: Array; showFirstAndLastPageBtn?: boolean; showJumper?: boolean; showPageNumber?: boolean; showPageSize?: boolean; showPreviousAndNextBtn?: boolean; size?: 'small' \| 'medium'; theme?: 'default' \| 'simple'; total?: number; totalContent?: string; onChange?: (pageInfo: PageInfo) => void; onCurrentChange?: (current: number, pageInfo: PageInfo) => void; onPageSizeChange?: (pageSize: number, pageInfo: PageInfo) => void; }` `interface PageInfo { current: number; previous: number; pageSize: number }`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +row-attributes | Object / Array / Function | - | `tr` attributes。Typescript: `TableRowAttributes` `type TableRowAttributes = HTMLElementAttributes \| ((params: { row: T; rowIndex: number; type: 'body' \| 'foot' }) => HTMLElementAttributes) \| Array>`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/common/common.ts)。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +row-class-name | String / Object / Array / Function | - | table `th` classname。Typescript: `ClassName \| ((params: RowClassNameParams) => ClassName)` `interface RowClassNameParams { row: T; rowIndex: number; rowKey?: string; type?: 'body' \| 'foot' }`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/common/common.ts)。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N row-key | String | 'id' | required。unique key for each row data | Y rowspan-and-colspan | Function | - | rowspan and colspan。Typescript: `TableRowspanAndColspanFunc` `type TableRowspanAndColspanFunc = (params: BaseTableCellParams) => RowspanColspan` `interface RowspanColspan { colspan?: number; rowspan?: number }`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N show-header | Boolean | true | show table header | N @@ -59,9 +63,102 @@ align | String | left | align type。options: left/right/center | N cell | String / Function | - | use cell to render table cell。Typescript: `string \| ((params: BaseTableCellParams) => string)` `interface BaseTableCellParams { row: T; rowIndex: number; col: BaseTableCol; colIndex: number }`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N class-name | String / Object / Array / Function | - | cell classnames。Typescript: `TableColumnClassName \| TableColumnClassName[]` `type TableColumnClassName = ClassName \| ((context: CellData) => ClassName)` `interface CellData extends BaseTableCellParams { type: 'th' \| 'td' }`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/common/common.ts)。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N col-key | String | - | unique key for column | N +ellipsis | Boolean / Object | false | ellipsis cell content | N +ellipsis-title | Boolean / Object | - | ellipsis title content。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N fixed | String | left | fixed current column to left or right。options: left/right | N min-width | String / Number | - | add CSS property `min-width` to HTML Element ``,Browsers with [TablesNG](https://docs.google.com/document/d/16PFD1GtMI9Zgwu0jtPaKZJ75Q2wyZ9EZnVbBacOfiNA/preview) support `minWidth` | N +title | String | - | th content。Typescript: `string` | N width | String / Number | - | column width | N +### BaseTableCol + +name | Description +-- | -- +ellipsis | ellipsis cell content +ellipsis-title | ellipsis title content。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) + + +### PrimaryTable Props + +name | type | default | description | required +-- | -- | -- | -- | -- +style | Object | - | CSS(Cascading Style Sheets) | N +custom-style | Object | - | CSS(Cascading Style Sheets),used to set style on virtual component | N +columns | Array | [] | table column configs。Typescript: `Array>` | N +display-columns | Array | - | Typescript: `CheckboxGroupValue` `type CheckboxGroupValue = Array`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +default-display-columns | Array | undefined | uncontrolled property。Typescript: `CheckboxGroupValue` `type CheckboxGroupValue = Array`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +drag-sort | String | - | dag sort。options: row/row-handler/col/row-handler-col/drag-col | N +drag-sort-options | Object | - | drag sort params。Typescript: `SortableOptions` | N +expand-icon | Boolean | true | to show expand icon. expand icon is set in first column。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +expand-on-row-click | Boolean | - | expand row on click | N +expanded-row | String | - | table expanded row, to show more detail information。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +expanded-row-keys | Array | [] | expanded row keys, row key value is from data[rowKey]。Typescript: `Array` | N +default-expanded-row-keys | Array | undefined | expanded row keys, row key value is from data[rowKey]。uncontrolled property。Typescript: `Array` | N +filter-row | String | - | filter value | N +filter-value | Object | - | filter value。Typescript: `FilterValue` `type FilterValue = { [key: string]: any }`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +default-filter-value | Object | undefined | filter value。uncontrolled property。Typescript: `FilterValue` `type FilterValue = { [key: string]: any }`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +hide-sort-tips | Boolean | - | hide sort tips | N +indeterminate-selected-row-keys | Array | - | indeterminate selected row keys, row key is from data[rowKey]。Typescript: `Array` | N +multiple-sort | Boolean | false | support multiple column fields sort | N +reserve-selected-row-on-paginate | Boolean | true | Controls whether selected rows are retained across pagination. When enabled, selections persist across all pages, allowing batch operations on multi-page data. If set to `false`, selections are confined to the current page and do not extend to other pages. | N +select-on-row-click | Boolean | - | select row data on row click | N +selected-row-keys | Array | [] | selected row keys, row key is from data[rowKey]。Typescript: `Array` | N +default-selected-row-keys | Array | undefined | selected row keys, row key is from data[rowKey]。uncontrolled property。Typescript: `Array` | N +show-sort-column-bg-color | Boolean | false | column shows sort bg color | N +sort | Object / Array | - | sort configs。Typescript: `TableSort` `type TableSort = SortInfo \| Array` `interface SortInfo { sortBy: string; descending: boolean }`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +default-sort | Object / Array | undefined | sort configs。uncontrolled property。Typescript: `TableSort` `type TableSort = SortInfo \| Array` `interface SortInfo { sortBy: string; descending: boolean }`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N + +### PrimaryTable Events + +name | params | description +-- | -- | -- +cell-click | `(detail: PrimaryTableCellEventContext)` | trigger on cell clicked。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts)。
`interface PrimaryTableCellEventContext { row: T; col: PrimaryTableCol; rowIndex: number; colIndex: number;}`
+change | `(data: TableChangeData, context: TableChangeContext)` | [see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts)。
`interface TableChangeData { sorter?: TableSort; filter?: FilterValue; pagination?: PaginationProps }`

`interface TableChangeContext { trigger: TableChangeTrigger; currentData?: T[] }`

`type TableChangeTrigger = 'filter' \| 'sorter' \| 'pagination'`
+column-change | `(detail: PrimaryTableColumnChange)` | [see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts)。
`interface PrimaryTableColumnChange { columns?: CheckboxGroupValue; currentColumn?: PrimaryTableCol; type?: 'check' \| 'uncheck'; e?: ChangeEvent }`
+data-change | `(data: Array, context: TableDataChangeContext)` | trigger on data changing。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts)。
`interface TableDataChangeContext { trigger: 'sort' }`
+display-columns-change | `(value: CheckboxGroupValue)` | [see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts)。
`import { CheckboxGroupValue } from '@Checkbox'`
+drag-sort | `(detail: DragSortContext)` | trigger on drag sort。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts)。
`interface DragSortContext { currentIndex: number; current: T; targetIndex: number; target: T; data: T[]; newData: T[]; currentData?: T[]; e: SortableEvent; sort: 'row' \| 'col' }`

`import { SortableEvent, SortableOptions } from 'sortablejs'`
+expand-change | `(expandedRowKeys: Array, options: ExpandOptions)` | trigger on expand row keys changing。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts)。
`interface ExpandOptions { expandedRowData: Array; currentRowData: T }`
+filter-change | `(filterValue: FilterValue, context: TableFilterChangeContext)` | trigger on filter value changing。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts)。
`interface TableFilterChangeContext { col?: PrimaryTableCol; trigger: 'filter-change' \| 'confirm' \| 'reset' \| 'clear' }`
+select-change | `(selectedRowKeys: Array, options: SelectOptions)` | trigger on select changing。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts)。
`interface SelectOptions { selectedRowData: Array; type: 'uncheck' \| 'check'; currentRowKey?: string; currentRowData?: T }`
+sort-change | `(sort: TableSort, options: SortOptions)` | trigger on sort changing。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts)。
`interface SortOptions { currentDataSource?: Array; col: PrimaryTableCol }`
+ +### PrimaryTable Slots + +name | Description +-- | -- +expand-icon | to show expand icon. expand icon is set in first column。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) +expanded-row | table expanded row, to show more detail information。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) +filter-icon | filter icon +filter-row | filter value +sort-icon | sort icon + +### PrimaryTableCol + +name | type | default | description | required +-- | -- | -- | -- | -- +check-props | Object / Function | - | checkbox or radio component properties。Typescript: `CheckProps` `type CheckProps = CheckboxProps \| RadioProps \| ((options: { row: T; rowIndex: number }) => CheckboxProps \| RadioProps)` `import { CheckboxProps } from '@Checkbox'`,[Radio API Documents](./radio?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +children | Array | - | grouping table head。Typescript: `Array>` | N +col-key | String | - | unique key for column | N +disabled | Function | - | disable table select action。Typescript: `(options: {row: T; rowIndex: number }) => boolean` | N +filter | Object | - | filter rules config。Typescript: `TableColumnFilter` | N +sort-type | String | all | sort options。options: desc/asc/all。Typescript: `SortType` `type SortType = 'desc' \| 'asc' \| 'all'`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +sorter | Boolean / Function | false | sort configs。Typescript: `boolean \| SorterFun` `type SorterFun = (a: T, b: T) => number`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +title | String | - | to render table head。Typescript: `string` | N +type | String | single | row select type。options: single/multiple | N + +### TableColumnFilter + +name | type | default | description | required +-- | -- | -- | -- | -- +attrs | Object | - | html attributes of component。Typescript: `HTMLElementAttributes`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/common/common.ts) | N +class-names | String | - | component class names。Typescript: `ClassName`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/common/common.ts) | N +confirm-events | Array | - | Typescript: `string[]` | N +label | String / Function | - | filter column title text, used to be showed in filter row。Typescript: `string` | N +list | Array | - | Typescript: `Array`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/common/common.ts) | N +popup-props | Object | - | Typescript: `PopupProps`,[Popup API Documents](./popup?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +props | Object | - | Typescript: `FilterProps` `type FilterProps = RadioProps \| CheckboxProps \| InputProps \| { [key: string]: any }`,[Input API Documents](./input?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +show-confirm-and-reset | Boolean | false | \- | N +type | String | - | Typescript: `FilterType` `type FilterType = 'input' \| 'single' \| 'multiple'`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N ### CSS Variables diff --git a/packages/components/table/README.md b/packages/components/table/README.md index 5884ab5dbd..427f843da1 100644 --- a/packages/components/table/README.md +++ b/packages/components/table/README.md @@ -71,8 +71,12 @@ fixed-rows | Array | - | 固定行(冻结行),示例:[M, N],表示冻 footer-summary | String | - | 表尾总结行 | N height | String / Number | - | 表格高度,超出后会出现滚动条。示例:100, '30%', '300'。值为数字类型,会自动加上单位 px。如果不是绝对固定表格高度,建议使用 `maxHeight` | N loading | Boolean | undefined | 加载中状态。值为 `true` 会显示默认加载中样式,可以通过 Function 和 插槽 自定义加载状态呈现内容和样式。值为 `false` 则会取消加载状态 | N +loading-mode | String | pull-refresh | 数据加载模式。可选项:pull-refresh/pagination | N loading-props | Object | - | 透传加载组件全部属性。TS 类型:`Partial`,[Loading API Documents](./loading?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N max-height | String / Number | - | 表格最大高度,超出后会出现滚动条。示例:100, '30%', '300'。值为数字类型,会自动加上单位 px | N +pagination | Object | - | 分页配置,值为空则不显示。具体 API 参考分页组件。当 `data` 数据长度超过分页大小时,会自动对本地数据 `data` 进行排序,如果不希望对于 `data` 进行排序,可以设置 `disableDataPage = true`。TS 类型:`PaginationProps` `interface PaginationProps { current?: number; defaultCurrent?: number; disabled?: boolean; foldedMaxPageBtn?: number; maxPageBtn?: number; pageEllipsisMode?: 'mid' \| 'both-ends'; pageSize?: number; defaultPageSize?: number; pageSizeOptions?: Array; showFirstAndLastPageBtn?: boolean; showJumper?: boolean; showPageNumber?: boolean; showPageSize?: boolean; showPreviousAndNextBtn?: boolean; size?: 'small' \| 'medium'; theme?: 'default' \| 'simple'; total?: number; totalContent?: string; onChange?: (pageInfo: PageInfo) => void; onCurrentChange?: (current: number, pageInfo: PageInfo) => void; onPageSizeChange?: (pageSize: number, pageInfo: PageInfo) => void; }` `interface PageInfo { current: number; previous: number; pageSize: number }`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +row-attributes | Object / Array / Function | - | HTML 标签 `tr` 的属性。类型为 Function 时,参数说明:`params.row` 表示行数据;`params.rowIndex` 表示行下标;`params.type=body` 表示属性作用于 `tbody` 中的元素;`params.type=foot` 表示属性作用于 `tfoot` 中的元素。
示例一:{ draggable: true },
示例二:[{ draggable: true }, { title: '超出省略显示' }]。
示例三:() => [{ draggable: true }]。TS 类型:`TableRowAttributes` `type TableRowAttributes = HTMLElementAttributes \| ((params: { row: T; rowIndex: number; type: 'body' \| 'foot' }) => HTMLElementAttributes) \| Array>`。[通用类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/common/common.ts)。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +row-class-name | String / Object / Array / Function | - | 行类名,泛型 T 指表格数据类型。`params.row` 表示行数据;`params.rowIndex` 表示行下标;`params.type=body` 表示类名作用于 `tbody` 中的元素;`params.type= tfoot` 表示类名作用于 `tfoot` 中的元素。TS 类型:`ClassName \| ((params: RowClassNameParams) => ClassName)` `interface RowClassNameParams { row: T; rowIndex: number; rowKey?: string; type?: 'body' \| 'foot' }`。[通用类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/common/common.ts)。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N row-key | String | 'id' | 必需。唯一标识一行数据的字段名,来源于 `data` 中的字段。如果是字段嵌套多层,可以设置形如 `item.a.id` 的方法 | Y rowspan-and-colspan | Function | - | 用于自定义合并单元格,泛型 T 指表格数据类型。示例:`({ row, col, rowIndex, colIndex }) => { rowspan: 2, colspan: 3 }`。TS 类型:`TableRowspanAndColspanFunc` `type TableRowspanAndColspanFunc = (params: BaseTableCellParams) => RowspanColspan` `interface RowspanColspan { colspan?: number; rowspan?: number }`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N show-header | Boolean | true | 是否显示表头 | N @@ -113,9 +117,102 @@ align | String | left | 列横向对齐方式。可选项:left/right/center | cell | String / Function | - | 自定义单元格渲染。默认使用 `colKey` 的值作为自定义当前列的插槽名称。
如果 `cell` 值类型为 Function 表示以函数形式渲染单元格。优先级高于 `render`。泛型 T 指表格数据类型。TS 类型:`string \| ((params: BaseTableCellParams) => string)` `interface BaseTableCellParams { row: T; rowIndex: number; col: BaseTableCol; colIndex: number }`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N class-name | String / Object / Array / Function | - | 列类名,值类型是 Function 使用返回值作为列类名;值类型不为 Function 时,值用于整列类名(含表头)。泛型 T 指表格数据类型。TS 类型:`TableColumnClassName \| TableColumnClassName[]` `type TableColumnClassName = ClassName \| ((context: CellData) => ClassName)` `interface CellData extends BaseTableCellParams { type: 'th' \| 'td' }`。[通用类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/common/common.ts)。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N col-key | String | - | 渲染列所需字段,值为 `serial-number` 表示当前列为「序号」列 | N +ellipsis | Boolean / Object | false | 单元格和表头内容超出时,是否显示省略号。如果仅希望单元格超出省略,可设置 `ellipsisTitle = false`。
值为 `true`,则超出省略浮层默认显示单元格内容;
值类型为 `Function` 则自定义超出省略浮中层显示的内容。
请注意单元格超出省略的两个基本点:1. 内容元素是内联元素或样式(自定义单元格内容时需特别注意);2. 内容超出父元素 | N +ellipsis-title | Boolean / Object | - | 表头内容超出时,是否显示省略号。优先级高于 `ellipsis`。
值为 `true`,则超出省略的浮层默认显示表头全部内容;
值类型为 `Function` 用于自定义超出省略浮层显示的表头内容。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N fixed | String | left | 固定列显示位置。可选项:left/right | N min-width | String / Number | - | 透传 CSS 属性 `min-width` 到 `` 元素。⚠️ 仅少部分浏览器支持,如:使用 [TablesNG](https://docs.google.com/document/d/16PFD1GtMI9Zgwu0jtPaKZJ75Q2wyZ9EZnVbBacOfiNA/preview) 渲染的 Chrome 浏览器支持 `minWidth` | N +title | String | - | 自定义表头渲染,优先级高于 render。TS 类型:`string` | N width | String / Number | - | 列宽,可以作为最小宽度使用。当列宽总和小于 `table` 元素时,浏览器根据宽度设置情况自动分配宽度;当列宽总和大于 `table` 元素,表现为定宽。可以同时调整 `table` 元素的宽度来达到自己想要的效果 | N +### BaseTableCol + +名称 | 描述 +-- | -- +ellipsis | 自定义 `ellipsis` 显示内容 +ellipsis-title | 自定义 `ellipsis-title` 显示内容。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) + + +### PrimaryTable Props + +名称 | 类型 | 默认值 | 描述 | 必传 +-- | -- | -- | -- | -- +style | Object | - | 样式 | N +custom-style | Object | - | 样式,一般用于开启虚拟化组件节点场景 | N +columns | Array | [] | 列配置,泛型 T 指表格数据类型。TS 类型:`Array>` | N +display-columns | Array | - | 列配置功能中,当前显示的列。TS 类型:`CheckboxGroupValue` `type CheckboxGroupValue = Array`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +default-display-columns | Array | undefined | 列配置功能中,当前显示的列。非受控属性。TS 类型:`CheckboxGroupValue` `type CheckboxGroupValue = Array`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +drag-sort | String | - | 拖拽排序方式,值为 `row` 表示行拖拽排序,这种方式无法进行文本复制,慎用。值为`row-handler` 表示通过拖拽手柄进行行拖拽排序。值为 `col` 表示列顺序拖拽。值为 `row-handler-col` 表示同时支持行拖拽和列拖拽。⚠️`drag-col` 已废弃,请勿使用。可选项:row/row-handler/col/row-handler-col/drag-col | N +drag-sort-options | Object | - | 拖拽排序扩展参数,具体参数见 [Sortable](https://github.com/SortableJS/Sortable)。TS 类型:`SortableOptions` | N +expand-icon | Boolean | true | 用于控制是否显示「展开图标列」,值为 `false` 则不会显示。可以精确到某一行是否显示,还可以自定义展开图标内容。`expandedRow` 存在时,该参数有效。支持全局配置 `GlobalConfigProvider`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +expand-on-row-click | Boolean | - | 是否允许点击行展开 | N +expanded-row | String | - | 展开行内容,泛型 T 指表格数据类型。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +expanded-row-keys | Array | [] | 展开行。TS 类型:`Array` | N +default-expanded-row-keys | Array | undefined | 展开行。非受控属性。TS 类型:`Array` | N +filter-row | String | - | 自定义过滤状态行及清空筛选等 | N +filter-value | Object | - | 过滤数据的值。TS 类型:`FilterValue` `type FilterValue = { [key: string]: any }`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +default-filter-value | Object | undefined | 过滤数据的值。非受控属性。TS 类型:`FilterValue` `type FilterValue = { [key: string]: any }`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +hide-sort-tips | Boolean | - | 隐藏排序文本提示,支持全局配置 `GlobalConfigProvider`,默认全局配置值为 `false` | N +indeterminate-selected-row-keys | Array | - | 半选状态行。选中行请更为使用 `selectedRowKeys` 控制。TS 类型:`Array` | N +multiple-sort | Boolean | false | 是否支持多列排序 | N +reserve-selected-row-on-paginate | Boolean | true | 行选中功能,是否在分页时保留上一页选中结果不清空。分页场景下,会全选所有页数据,保留跨分页数据。值为 `false` 则表示全部选中操作停留在当前页,不跨分页。 | N +select-on-row-click | Boolean | - | 是否在点击整行时选中 | N +selected-row-keys | Array | [] | 选中行。半选状态行请更为使用 `indeterminateSelectedRowKeys` 控制。TS 类型:`Array` | N +default-selected-row-keys | Array | undefined | 选中行。半选状态行请更为使用 `indeterminateSelectedRowKeys` 控制。非受控属性。TS 类型:`Array` | N +show-sort-column-bg-color | Boolean | false | 当前排序列是否显示背景色 | N +sort | Object / Array | - | 排序控制。sortBy 排序字段;descending 是否进行降序排列。值为数组时,表示正进行多字段排序。TS 类型:`TableSort` `type TableSort = SortInfo \| Array` `interface SortInfo { sortBy: string; descending: boolean }`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +default-sort | Object / Array | undefined | 排序控制。sortBy 排序字段;descending 是否进行降序排列。值为数组时,表示正进行多字段排序。非受控属性。TS 类型:`TableSort` `type TableSort = SortInfo \| Array` `interface SortInfo { sortBy: string; descending: boolean }`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N + +### PrimaryTable Events + +名称 | 参数 | 描述 +-- | -- | -- +cell-click | `(detail: PrimaryTableCellEventContext)` | 单元格点击时触发。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts)。
`interface PrimaryTableCellEventContext { row: T; col: PrimaryTableCol; rowIndex: number; colIndex: number;}`
+change | `(data: TableChangeData, context: TableChangeContext)` | 分页、排序、过滤等内容变化时触发,泛型 T 指表格数据类型,`currentData` 表示变化后的数据。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts)。
`interface TableChangeData { sorter?: TableSort; filter?: FilterValue; pagination?: PaginationProps }`

`interface TableChangeContext { trigger: TableChangeTrigger; currentData?: T[] }`

`type TableChangeTrigger = 'filter' \| 'sorter' \| 'pagination'`
+column-change | `(detail: PrimaryTableColumnChange)` | 确认操作之前列配置发生变化时触发。`context.columns` 表示已选中的列;`context.currentColumn` 表示本次变化操作的列,值不存在表示全选操作;`context.type` 表示当前操作属于选中列或是取消列。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts)。
`interface PrimaryTableColumnChange { columns?: CheckboxGroupValue; currentColumn?: PrimaryTableCol; type?: 'check' \| 'uncheck'; e?: ChangeEvent }`
+data-change | `(data: Array, context: TableDataChangeContext)` | 本地数据排序导致 `data` 变化时触发,第一个参数指变化后的数据,第二个参数 `context.trigger` 表示触发本次变化的来源。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts)。
`interface TableDataChangeContext { trigger: 'sort' }`
+display-columns-change | `(value: CheckboxGroupValue)` | 确认列配置时触发。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts)。
`import { CheckboxGroupValue } from '@Checkbox'`
+drag-sort | `(detail: DragSortContext)` | 拖拽排序时触发,`data` 表示排序前的数据,`newData` 表示拖拽排序结束后的新数据,`sort=row` 表示行拖拽事件触发,`sort=col` 表示列拖拽事件触发。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts)。
`interface DragSortContext { currentIndex: number; current: T; targetIndex: number; target: T; data: T[]; newData: T[]; currentData?: T[]; e: SortableEvent; sort: 'row' \| 'col' }`

`import { SortableEvent, SortableOptions } from 'sortablejs'`
+expand-change | `(expandedRowKeys: Array, options: ExpandOptions)` | 展开行发生变化时触发,泛型 T 指表格数据类型。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts)。
`interface ExpandOptions { expandedRowData: Array; currentRowData: T }`
+filter-change | `(filterValue: FilterValue, context: TableFilterChangeContext)` | 过滤参数发生变化时触发,泛型 T 指表格数据类型。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts)。
`interface TableFilterChangeContext { col?: PrimaryTableCol; trigger: 'filter-change' \| 'confirm' \| 'reset' \| 'clear' }`
+select-change | `(selectedRowKeys: Array, options: SelectOptions)` | 选中行发生变化时触发,泛型 T 指表格数据类型。两个参数,第一个参数为选中行 keys,第二个参数为更多参数,具体如下:`type = uncheck` 表示当前行操作为「取消行选中」;`type = check` 表示当前行操作为「行选中」; `currentRowKey` 表示当前操作行的 rowKey 值; `currentRowData` 表示当前操作行的行数据。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts)。
`interface SelectOptions { selectedRowData: Array; type: 'uncheck' \| 'check'; currentRowKey?: string; currentRowData?: T }`
+sort-change | `(sort: TableSort, options: SortOptions)` | 排序发生变化时触发。其中 sortBy 表示当前排序的字段,sortType 表示排序的方式,currentDataSource 表示 sorter 排序后的结果,col 表示列配置。sort 值类型为数组时表示多字段排序。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts)。
`interface SortOptions { currentDataSource?: Array; col: PrimaryTableCol }`
+ +### PrimaryTable Slots + +名称 | 描述 +-- | -- +expand-icon | 自定义 `expand-icon` 显示内容。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) +expanded-row | 自定义 `expanded-row` 显示内容。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) +filter-icon | 自定义过滤图标,支持全局配置 `GlobalConfigProvider` +filter-row | 自定义 `filter-row` 显示内容 +sort-icon | 自定义排序图标,支持全局配置 `GlobalConfigProvider` + +### PrimaryTableCol + +名称 | 类型 | 默认值 | 描述 | 必传 +-- | -- | -- | -- | -- +check-props | Object / Function | - | 透传参数,`colKey` 值为 `row-select` 时,配置有效。具体定义参考 Checkbox 组件 和 Radio 组件。泛型 T 指表格数据类型。TS 类型:`CheckProps` `type CheckProps = CheckboxProps \| RadioProps \| ((options: { row: T; rowIndex: number }) => CheckboxProps \| RadioProps)` `import { CheckboxProps } from '@Checkbox'`,[Radio API Documents](./radio?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +children | Array | - | 用于多级表头,泛型 T 指表格数据类型。TS 类型:`Array>` | N +col-key | String | - | 渲染列所需字段,必须唯一。值为 `row-select` 表示当前列为行选中操作列。值为 `drag` 表示当前列为拖拽排序操作列。值为 `serial-number` 表示当前列为「序号」列 | N +disabled | Function | - | 是否禁用行选中,`colKey` 值为 `row-select` 时,配置有效。TS 类型:`(options: {row: T; rowIndex: number }) => boolean` | N +filter | Object | - | 过滤规则,支持多选(multiple)、单选(single)、输入框(input) 等三种形式。想要自定义过滤组件,可通过 `filter.component` 实现,自定义过滤组件需要包含参数 value 和事件 change。更多信息请查看当前页面中 `TableColumnFilter` 的详细文档。TS 类型:`TableColumnFilter` | N +sort-type | String | all | 当前列支持排序的方式,desc 表示当前列只能进行降序排列;asc 表示当前列只能进行升序排列;all 表示当前列既可升序排列,又可以降序排列。可选项:desc/asc/all。TS 类型:`SortType` `type SortType = 'desc' \| 'asc' \| 'all'`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +sorter | Boolean / Function | false | 该列是否支持排序。值为 true 表示该列支持排序;值类型为函数,表示对本地数据 `data` 进行排序,返回值参考 [MDN Array.sort](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)。泛型 T 指表格数据类型。TS 类型:`boolean \| SorterFun` `type SorterFun = (a: T, b: T) => number`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +title | String | - | 自定义表头渲染。值类型为 string 表示使用插槽渲染,插槽名称为 title 的值。优先级高于 render。TS 类型:`string` | N +type | String | single | `colKey` 值为 `row-select` 时表示行选中列,有两种模式:单选和多选。 `type=single` 表示单选,`type=multiple` 表示多选。可选项:single/multiple | N + +### TableColumnFilter + +名称 | 类型 | 默认值 | 描述 | 必传 +-- | -- | -- | -- | -- +attrs | Object | - | 用于透传筛选器属性到自定义组件 `component`,HTML 原生属性。TS 类型:`HTMLElementAttributes`。[通用类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/common/common.ts) | N +class-names | String | - | 透传类名到自定义组件 `component`。TS 类型:`ClassName`。[通用类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/common/common.ts) | N +confirm-events | Array | - | 哪些事件触发后会进行过滤搜索(确认按钮无需配置,会默认触发搜索)。输入框组件示例:`confirmEvents: ['onEnter']`。TS 类型:`string[]` | N +label | String / Function | - | 过滤项标题文本,显示在“过滤结果行”中的列标题描述。一般用于表头标题和过滤文本行中的列标题不一样的场景。TS 类型:`string` | N +list | Array | - | 用于配置当前筛选器可选值有哪些,仅当 `filter.type` 等于 `single` 或 `multiple` 时有效。TS 类型:`Array`。[通用类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/common/common.ts) | N +popup-props | Object | - | 透传 Popup 组件全部属性到筛选器浮层。TS 类型:`PopupProps`,[Popup API Documents](./popup?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +props | Object | - | 用于透传筛选器属性到自定义组件 `component`,可以对筛选器进行任何原组件支持的属性配置。TS 类型:`FilterProps` `type FilterProps = RadioProps \| CheckboxProps \| InputProps \| { [key: string]: any }`,[Input API Documents](./input?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N +show-confirm-and-reset | Boolean | false | 是否显示重置和确认。值为真,过滤事件(filter-change)会在确定时触发;值为假,则数据变化时会立即触发过滤事件 | N +type | String | - | 用于设置筛选器类型:单选按钮筛选器、复选框筛选器、输入框筛选器。更多复杂组件,请更为使用 `component` 自定义任意组件。TS 类型:`FilterType` `type FilterType = 'input' \| 'single' \| 'multiple'`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/table/type.ts) | N ### CSS Variables diff --git a/packages/components/table/__test__/demo.test.js b/packages/components/table/__test__/demo.test.js index 0a41933e11..818cf796aa 100644 --- a/packages/components/table/__test__/demo.test.js +++ b/packages/components/table/__test__/demo.test.js @@ -5,7 +5,17 @@ import path from 'path'; import simulate from 'miniprogram-simulate'; -const mapper = ['base', 'bordered', 'rowspan-colspan', 'scroll', 'stripe']; +const mapper = [ + 'base', + 'bordered', + 'rowspan-colspan', + 'scroll', + 'stripe', + 'sort', + 'select', + 'loading', + 'custom-row-style', +]; describe('Table', () => { mapper.forEach((demoName) => { diff --git a/packages/components/table/_example/custom-row-style/index.js b/packages/components/table/_example/custom-row-style/index.js new file mode 100644 index 0000000000..7b37d0e16f --- /dev/null +++ b/packages/components/table/_example/custom-row-style/index.js @@ -0,0 +1,55 @@ +import SkylineBehavior from '@behaviors/skyline.js'; + +Component({ + behaviors: [SkylineBehavior], + data: { + columns: [ + { colKey: 'applicant', title: '申请人', width: 100, fixed: 'left' }, + { colKey: 'status', title: '审批状态', width: 120 }, + { + colKey: 'time', + title: '申请耗时(天)', + width: 120, + align: 'center', + className: ({ row }) => (row.time >= 9 ? 'custom-cell-class-name' : ''), + }, + { + colKey: 'channel', + title: '签署方式', + width: 100, + align: 'right', + className: () => 'custom-cell-class-name', + }, + { colKey: 'detail.email', title: '邮箱地址', width: 160, ellipsis: true }, + ], + data: [], + }, + lifetimes: { + attached() { + const data = []; + const total = 5; + for (let i = 0; i < total; i += 1) { + data.push({ + id: i + 1, + applicant: ['贾明', '张三', '王芳'][i % 3], + status: ['审批通过', '审批失败', '审批过期'][i % 3], + channel: ['电子签署', '纸质签署', '纸质签署'][i % 3], + detail: { + email: ['w.cezkdudy@lhll.au', 'r.nmgw@peurezgn.sl', 'p.cumx@rampblpa.ru'][i % 3], + }, + matters: ['宣传物料制作费用', 'algolia 服务报销', '相关周边制作费', '激励奖品快递费'][i % 4], + time: [2, 10, 1][i % 3], + }); + } + + this.setData({ + data, + }); + }, + }, + methods: { + onRowClick(e) { + console.log('[row-click]', e.detail); + }, + }, +}); diff --git a/packages/components/table/_example/custom-row-style/index.json b/packages/components/table/_example/custom-row-style/index.json new file mode 100644 index 0000000000..e3c621db08 --- /dev/null +++ b/packages/components/table/_example/custom-row-style/index.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "t-table": "tdesign-miniprogram/table/table" + } +} diff --git a/packages/components/table/_example/custom-row-style/index.wxml b/packages/components/table/_example/custom-row-style/index.wxml new file mode 100644 index 0000000000..ae276a6964 --- /dev/null +++ b/packages/components/table/_example/custom-row-style/index.wxml @@ -0,0 +1,8 @@ + diff --git a/packages/components/table/_example/custom-row-style/index.wxss b/packages/components/table/_example/custom-row-style/index.wxss new file mode 100644 index 0000000000..58a8bf92a5 --- /dev/null +++ b/packages/components/table/_example/custom-row-style/index.wxss @@ -0,0 +1,5 @@ +/* 自定义单元格类名样式 */ +.custom-cell-class-name { + color: orange; + font-weight: bold; +} diff --git a/packages/components/table/_example/loading/index.js b/packages/components/table/_example/loading/index.js new file mode 100644 index 0000000000..b3c032302e --- /dev/null +++ b/packages/components/table/_example/loading/index.js @@ -0,0 +1,42 @@ +import SkylineBehavior from '@behaviors/skyline.js'; + +Component({ + behaviors: [SkylineBehavior], + data: { + columns: [ + { colKey: 'projName', title: '项目名称', width: 80, ellipsis: true }, + { colKey: 'projTag', title: '标签', width: 80 }, + { colKey: 'options', title: '操作', align: 'center', width: 120 }, + ], + data: [], + total: 9, + pagination: { + defaultCurrent: 1, + defaultPageSize: 5, + total: 9, + }, + }, + lifetimes: { + attached() { + const data = []; + const total = 9; + for (let i = 0; i < total; i += 1) { + data.push({ + index: i + 1, + projName: ['项目名称', '项目名称', '项目名称'][i % 3], + projTag: ['默认标签', '默认标签', '默认标签'][i % 3], + options: { + admin: ['管理', '管理', '管理'][i % 3], + delete: ['删除', '删除', '删除'][i % 3], + }, + }); + } + this.setData({ data }); + }, + }, + methods: { + onPageChange(e) { + console.log('[page-change]', e.detail); + }, + }, +}); diff --git a/packages/components/table/_example/loading/index.json b/packages/components/table/_example/loading/index.json new file mode 100644 index 0000000000..e3c621db08 --- /dev/null +++ b/packages/components/table/_example/loading/index.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "t-table": "tdesign-miniprogram/table/table" + } +} diff --git a/packages/components/table/_example/loading/index.wxml b/packages/components/table/_example/loading/index.wxml new file mode 100644 index 0000000000..085577caf2 --- /dev/null +++ b/packages/components/table/_example/loading/index.wxml @@ -0,0 +1,23 @@ + + 上拉加载 + + 分页加载 + + diff --git a/packages/components/table/_example/loading/index.wxss b/packages/components/table/_example/loading/index.wxss new file mode 100644 index 0000000000..c7d50724f8 --- /dev/null +++ b/packages/components/table/_example/loading/index.wxss @@ -0,0 +1,9 @@ +.loading-demo { + padding: 0 16rpx; +} + +.loading-demo__title { + font-size: 28rpx; + margin: 24rpx 0 16rpx; + color: var(--td-text-color-secondary); +} diff --git a/packages/components/table/_example/select/index.js b/packages/components/table/_example/select/index.js new file mode 100644 index 0000000000..57286e0edc --- /dev/null +++ b/packages/components/table/_example/select/index.js @@ -0,0 +1,52 @@ +import SkylineBehavior from '@behaviors/skyline.js'; + +Component({ + behaviors: [SkylineBehavior], + data: { + selectedRowKeys1: [], + selectedRowKeys2: [], + multipleColumns: [ + { colKey: 'row-select', type: 'multiple' }, + { colKey: 'projName', title: '项目名称' }, + { colKey: 'projTag', title: '项目名称' }, + { colKey: 'options', title: '操作', align: 'center' }, + ], + singleColumns: [ + { colKey: 'row-select', type: 'single' }, + { colKey: 'projName', title: '项目名称' }, + { colKey: 'projTag', title: '项目名称' }, + { colKey: 'options', title: '操作', align: 'center' }, + ], + data: [], + }, + lifetimes: { + attached() { + const data = []; + const total = 5; + for (let i = 0; i < total; i += 1) { + data.push({ + index: i + 1, + projName: ['项目名称1', '项目名称2', '项目名称3'][i % 3], + projTag: ['默认标签', '默认标签', '默认标签'][i % 3], + options: { + admin: ['管理', '管理', '管理'][i % 3], + delete: ['删除', '删除', '删除'][i % 3], + }, + }); + } + this.setData({ data }); + }, + }, + methods: { + onSelectChange1(e) { + const { selectedRowKeys } = e.detail; + console.log('onSelectChange1', selectedRowKeys); + this.setData({ selectedRowKeys1: selectedRowKeys }); + }, + onSelectChange2(e) { + const { selectedRowKeys } = e.detail; + console.log('onSelectChange2', selectedRowKeys); + this.setData({ selectedRowKeys2: selectedRowKeys }); + }, + }, +}); diff --git a/packages/components/table/_example/select/index.json b/packages/components/table/_example/select/index.json new file mode 100644 index 0000000000..e3c621db08 --- /dev/null +++ b/packages/components/table/_example/select/index.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "t-table": "tdesign-miniprogram/table/table" + } +} diff --git a/packages/components/table/_example/select/index.wxml b/packages/components/table/_example/select/index.wxml new file mode 100644 index 0000000000..9b37ed4eb8 --- /dev/null +++ b/packages/components/table/_example/select/index.wxml @@ -0,0 +1,22 @@ + + 单选 + + 多选 + + diff --git a/packages/components/table/_example/select/index.wxss b/packages/components/table/_example/select/index.wxss new file mode 100644 index 0000000000..586fd2859c --- /dev/null +++ b/packages/components/table/_example/select/index.wxss @@ -0,0 +1,9 @@ +.select-demo { + padding: 0 16rpx; +} + +.select-demo__title { + font-size: 28rpx; + margin: 24rpx 0 16rpx; + color: var(--td-text-color-secondary); +} diff --git a/packages/components/table/_example/sort/index.js b/packages/components/table/_example/sort/index.js new file mode 100644 index 0000000000..3ac31daba5 --- /dev/null +++ b/packages/components/table/_example/sort/index.js @@ -0,0 +1,53 @@ +import SkylineBehavior from '@behaviors/skyline.js'; + +const statusNameListMap = { + 0: '审批通过', + 1: '审批失败', + 2: '审批过期', +}; + +Component({ + behaviors: [SkylineBehavior], + data: { + sort: null, + columns: [ + { colKey: 'applicant', title: '申请人', align: 'center' }, + { + colKey: 'status', + title: '申请状态', + width: 120, + align: 'center', + cell: ({ row }) => statusNameListMap[row.status] || '', + }, + { colKey: 'channel', title: '签署方式', width: 120, align: 'center' }, + { colKey: 'email', title: 'Email', width: 180, align: 'center' }, + { colKey: 'createTime', title: 'Date', width: 100, align: 'center', sorter: true }, + ], + data: [], + }, + lifetimes: { + attached() { + const initData = []; + const total = 5; + for (let i = 0; i < total; i += 1) { + initData.push({ + key: String(i + 1), + applicant: ['贾明', '张三', '王芳'][i % 3], + status: i % 3, + channel: ['电子签署', '纸质签署', '纸质签署'][i % 3], + email: ['w.cezkdudy@lhll.au', 'r.nmgw@peurezgn.sl', 'p.cumx@rampblpa.ru'][i % 3], + matters: ['宣传物料制作费用', 'algolia 服务报销', '相关周边制作费', '激励奖品快递费'][i % 4], + time: [2, 3, 1, 4][i % 4], + createTime: [20220101, 20220201, 20220301, 20220401, 20220501][i % 4], + }); + } + this.setData({ data: initData }); + }, + }, + methods: { + onSortChange(e) { + console.log('[sort-change]', e.detail); + this.setData({ sort: e.detail }); + }, + }, +}); diff --git a/packages/components/table/_example/sort/index.json b/packages/components/table/_example/sort/index.json new file mode 100644 index 0000000000..e3c621db08 --- /dev/null +++ b/packages/components/table/_example/sort/index.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "t-table": "tdesign-miniprogram/table/table" + } +} diff --git a/packages/components/table/_example/sort/index.wxml b/packages/components/table/_example/sort/index.wxml new file mode 100644 index 0000000000..3b01680af6 --- /dev/null +++ b/packages/components/table/_example/sort/index.wxml @@ -0,0 +1,9 @@ + diff --git a/packages/components/table/_example/sort/index.wxss b/packages/components/table/_example/sort/index.wxss new file mode 100644 index 0000000000..ddc4437b06 --- /dev/null +++ b/packages/components/table/_example/sort/index.wxss @@ -0,0 +1 @@ +/* sort demo 无额外样式 */ diff --git a/packages/components/table/_example/table.json b/packages/components/table/_example/table.json index 0dd71e440d..4bed76ab6a 100644 --- a/packages/components/table/_example/table.json +++ b/packages/components/table/_example/table.json @@ -6,6 +6,10 @@ "bordered": "./bordered", "stripe": "./stripe", "scroll": "./scroll", - "rowspan-colspan": "./rowspan-colspan" + "rowspan-colspan": "./rowspan-colspan", + "sort": "./sort", + "select": "./select", + "loading": "./loading", + "custom-row-style": "./custom-row-style" } } diff --git a/packages/components/table/_example/table.wxml b/packages/components/table/_example/table.wxml index 234f169c11..2409389299 100644 --- a/packages/components/table/_example/table.wxml +++ b/packages/components/table/_example/table.wxml @@ -5,7 +5,7 @@ desc="表格常用于展示同类结构下的多种数据,易于组织、对比和分析等,并可对数据进行搜索、筛选、排序等操作。" notice="渲染框架支持情况:WebView" /> - + + + + + diff --git a/packages/components/table/base-table-props.ts b/packages/components/table/base-table-props.ts index 912703aaa6..487240b114 100644 --- a/packages/components/table/base-table-props.ts +++ b/packages/components/table/base-table-props.ts @@ -47,6 +47,11 @@ const props: TdBaseTableProps = { type: null, value: undefined, }, + /** 数据加载模式 */ + loadingMode: { + type: String, + value: 'pull-refresh', + }, /** 透传加载组件全部属性 */ loadingProps: { type: Object, @@ -55,6 +60,18 @@ const props: TdBaseTableProps = { maxHeight: { type: null, }, + /** 分页配置,值为空则不显示。具体 API 参考分页组件。当 `data` 数据长度超过分页大小时,会自动对本地数据 `data` 进行排序,如果不希望对于 `data` 进行排序,可以设置 `disableDataPage = true` */ + pagination: { + type: Object, + }, + /** HTML 标签 `tr` 的属性。类型为 Function 时,参数说明:`params.row` 表示行数据;`params.rowIndex` 表示行下标;`params.type=body` 表示属性作用于 `tbody` 中的元素;`params.type=foot` 表示属性作用于 `tfoot` 中的元素。
示例一:{ draggable: true },
示例二:[{ draggable: true }, { title: '超出省略显示' }]。
示例三:() => [{ draggable: true }] */ + rowAttributes: { + type: null, + }, + /** 行类名,泛型 T 指表格数据类型。`params.row` 表示行数据;`params.rowIndex` 表示行下标;`params.type=body` 表示类名作用于 `tbody` 中的元素;`params.type= tfoot` 表示类名作用于 `tfoot` 中的元素 */ + rowClassName: { + type: null, + }, /** 唯一标识一行数据的字段名,来源于 `data` 中的字段。如果是字段嵌套多层,可以设置形如 `item.a.id` 的方法 */ rowKey: { type: String, diff --git a/packages/components/table/primary-table-props.ts b/packages/components/table/primary-table-props.ts new file mode 100644 index 0000000000..d2334a32b6 --- /dev/null +++ b/packages/components/table/primary-table-props.ts @@ -0,0 +1,115 @@ +/* eslint-disable */ + +/** + * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC + * */ + +import { TdPrimaryTableProps } from './type'; +const props: TdPrimaryTableProps = { + /** 列配置,泛型 T 指表格数据类型 */ + columns: { + type: Array, + value: [], + }, + /** 列配置功能中,当前显示的列 */ + displayColumns: { + type: Array, + value: null, + }, + /** 列配置功能中,当前显示的列,非受控属性 */ + defaultDisplayColumns: { + type: Array, + }, + /** 拖拽排序方式,值为 `row` 表示行拖拽排序,这种方式无法进行文本复制,慎用。值为`row-handler` 表示通过拖拽手柄进行行拖拽排序。值为 `col` 表示列顺序拖拽。值为 `row-handler-col` 表示同时支持行拖拽和列拖拽。⚠️`drag-col` 已废弃,请勿使用 */ + dragSort: { + type: String, + }, + /** 拖拽排序扩展参数,具体参数见 [Sortable](https://github.com/SortableJS/Sortable) */ + dragSortOptions: { + type: Object, + }, + /** 用于控制是否显示「展开图标列」,值为 `false` 则不会显示。可以精确到某一行是否显示,还可以自定义展开图标内容。`expandedRow` 存在时,该参数有效。支持全局配置 `GlobalConfigProvider` */ + expandIcon: { + type: Boolean, + value: true, + }, + /** 是否允许点击行展开 */ + expandOnRowClick: { + type: Boolean, + }, + /** 展开行内容,泛型 T 指表格数据类型 */ + expandedRow: { + type: String, + }, + /** 展开行 */ + expandedRowKeys: { + type: Array, + value: null, + }, + /** 展开行,非受控属性 */ + defaultExpandedRowKeys: { + type: Array, + value: [], + }, + /** 自定义过滤状态行及清空筛选等 */ + filterRow: { + type: String, + }, + /** 过滤数据的值 */ + filterValue: { + type: Object, + value: null, + }, + /** 过滤数据的值,非受控属性 */ + defaultFilterValue: { + type: Object, + }, + /** 隐藏排序文本提示,支持全局配置 `GlobalConfigProvider`,默认全局配置值为 `false` */ + hideSortTips: { + type: Boolean, + }, + /** 半选状态行。选中行请更为使用 `selectedRowKeys` 控制 */ + indeterminateSelectedRowKeys: { + type: Array, + }, + /** 是否支持多列排序 */ + multipleSort: { + type: Boolean, + value: false, + }, + /** 行选中功能,是否在分页时保留上一页选中结果不清空。分页场景下,会全选所有页数据,保留跨分页数据。值为 `false` 则表示全部选中操作停留在当前页,不跨分页。 */ + reserveSelectedRowOnPaginate: { + type: Boolean, + value: true, + }, + /** 是否在点击整行时选中 */ + selectOnRowClick: { + type: Boolean, + }, + /** 选中行。半选状态行请更为使用 `indeterminateSelectedRowKeys` 控制 */ + selectedRowKeys: { + type: Array, + value: null, + }, + /** 选中行。半选状态行请更为使用 `indeterminateSelectedRowKeys` 控制,非受控属性 */ + defaultSelectedRowKeys: { + type: Array, + value: [], + }, + /** 当前排序列是否显示背景色 */ + showSortColumnBgColor: { + type: Boolean, + value: false, + }, + /** 排序控制。sortBy 排序字段;descending 是否进行降序排列。值为数组时,表示正进行多字段排序 */ + sort: { + type: null, + value: null, + }, + /** 排序控制。sortBy 排序字段;descending 是否进行降序排列。值为数组时,表示正进行多字段排序,非受控属性 */ + defaultSort: { + type: null, + }, +}; + +export default props; diff --git a/packages/components/table/table.json b/packages/components/table/table.json index f20e16478f..066ff1ea8b 100644 --- a/packages/components/table/table.json +++ b/packages/components/table/table.json @@ -2,6 +2,13 @@ "component": true, "styleIsolation": "apply-shared", "usingComponents": { - "t-loading": "../loading/loading" + "t-loading": "../loading/loading", + "t-button": "../button/button", + "t-checkbox": "../checkbox/checkbox", + "t-checkbox-group": "../checkbox-group/checkbox-group", + "t-radio": "../radio/radio", + "t-radio-group": "../radio-group/radio-group", + "t-icon": "../icon/icon", + "t-popup": "../popup/popup" } } diff --git a/packages/components/table/table.less b/packages/components/table/table.less index aa60ecd112..598a3a1541 100644 --- a/packages/components/table/table.less +++ b/packages/components/table/table.less @@ -1,6 +1,7 @@ @import '../common/style/base.less'; @table-prefix: ~'@{prefix}-table'; +@table-icon-size: @font-size-m; // 变量 @table-border-color: var(--td-table-border-color, @component-border); @@ -416,4 +417,24 @@ border-left: @table-fixed-cell-border; } } + + &__cell-check { + display: flex; + align-items: center; + justify-content: center; + + --td-radio-vertical-padding: 0; + --td-checkbox-vertical-padding: 0; + --td-radio-icon-size: 40rpx; + --td-checkbox-icon-size: 40rpx; + } + + &__cell-check-icon { + font-size: @table-icon-size; + width: @table-icon-size; + height: @table-icon-size; + flex: none; + margin-top: 0; + margin-right: 0; + } } diff --git a/packages/components/table/table.ts b/packages/components/table/table.ts index 1c2b28cb4a..f158aa6a0d 100644 --- a/packages/components/table/table.ts +++ b/packages/components/table/table.ts @@ -1,8 +1,9 @@ import { SuperComponent, wxComponent } from '../common/src/index'; import config from '../common/config'; import usingConfig from '../mixins/using-config'; -import props from './base-table-props'; -import type { BaseTableCol, TableRowData } from './type'; +import baseTableProps from './base-table-props'; +import primaryTableProps from './primary-table-props'; +import type { BaseTableCol, PrimaryTableCol, TableRowData } from './type'; import { formatCSSUnit, get, @@ -17,6 +18,8 @@ import { const { prefix } = config; const componentName = 'table'; +const props = { ...baseTableProps, ...primaryTableProps}; + @wxComponent() export default class Table extends SuperComponent { behaviors = [usingConfig({ componentName })]; @@ -48,6 +51,12 @@ export default class Table extends SuperComponent { scrollableToLeft: false, scrollableToRight: false, contentClasses: '', + // 选中 + innerSelectedRowKeys: [] as any[], + // 全选状态 + allChecked: false, + // 半选状态 + isIndeterminateChecked: false, }; observers = { @@ -56,10 +65,22 @@ export default class Table extends SuperComponent { ) { this.updateTable(); }, + // 监听选中属性变化(受控模式) + selectedRowKeys(val: any) { + if (val) { + this.setData({ innerSelectedRowKeys: val }); + this.updateTable(); + } + }, }; lifetimes = { attached(this: any) { + // 初始化非受控默认值 + const { defaultSelectedRowKeys } = this.properties; + if (defaultSelectedRowKeys && !this.data.innerSelectedRowKeys?.length) { + this.setData({ innerSelectedRowKeys: defaultSelectedRowKeys }); + } this.updateTable(); }, }; @@ -82,8 +103,25 @@ export default class Table extends SuperComponent { cellEmptyContent, rowKey, fixedRows, + selectedRowKeys, + defaultSelectedRowKeys, + indeterminateSelectedRowKeys, + reserveSelectedRowOnPaginate, } = this.properties; - const { classPrefix } = this.data; + const { classPrefix, innerSelectedRowKeys } = this.data; + + // 使用受控值或非受控值 + let tSelectedRowKeys = selectedRowKeys || defaultSelectedRowKeys || innerSelectedRowKeys || []; + + // reserveSelectedRowOnPaginate 为 false 时,分页切换清空不在当前页的选中项 + if (reserveSelectedRowOnPaginate === false && !selectedRowKeys && innerSelectedRowKeys.length > 0) { + const currentDataKeys = (data || []).map((row: TableRowData) => get(row, rowKey || 'id')); + const filteredKeys = innerSelectedRowKeys.filter((key: any) => currentDataKeys.includes(key)); + if (filteredKeys.length !== innerSelectedRowKeys.length) { + this.setData({ innerSelectedRowKeys: filteredKeys }); + tSelectedRowKeys = filteredKeys; + } + } // 解析 fixedRows const fixedTopRows = (fixedRows && (fixedRows as number[])[0]) || 0; @@ -173,14 +211,19 @@ export default class Table extends SuperComponent { // 列样式 const defaultColWidth = tableLayout === 'fixed' ? '80px' : undefined; const colStyles = (columns || []).map((col: BaseTableCol, colIndex: number) => { - const width = formatCSSUnit(col.width || defaultColWidth); - const minWidth = - !formatCSSUnit(col.width || defaultColWidth) && !col.minWidth && tableLayout === 'fixed' - ? '80px' - : formatCSSUnit(col.minWidth); + const isSelectCol = (col as PrimaryTableCol).type === 'multiple' || (col as PrimaryTableCol).type === 'single'; + const selectColWidth = '50px'; + const width = formatCSSUnit(col.width || (isSelectCol ? selectColWidth : defaultColWidth)); + let minWidth; + const hasNoWidth = !formatCSSUnit(col.width || (isSelectCol ? selectColWidth : defaultColWidth)); + if (hasNoWidth && !col.minWidth && tableLayout === 'fixed') { + minWidth = isSelectCol ? selectColWidth : '80px'; + } else { + minWidth = formatCSSUnit(col.minWidth); + } const styles: string[] = []; // 当列设置了固定宽度时,使用 flex: 0 0 auto 防止被 flex 压缩,支持横向滚动 - if (col.width) { + if (col.width || isSelectCol) { styles.push('flex: 0 0 auto'); } if (width) styles.push(`width: ${width}`); @@ -203,6 +246,10 @@ export default class Table extends SuperComponent { if (col.fixed === 'right') classes.push(`${classPrefix}__cell--fixed-right`); if (colIndex === lastFixedLeftIndex) classes.push(`${classPrefix}__cell--fixed-left-last`); if (colIndex === firstFixedRightIndex) classes.push(`${classPrefix}__cell--fixed-right-first`); + // 选中列表头 + if ((col as PrimaryTableCol).type === 'multiple' || (col as PrimaryTableCol).type === 'single') { + classes.push(`${classPrefix}__cell-check`); + } classes.push(getColumnClassName(col, { col, colIndex, type: 'th' })); return classes.filter(Boolean).join(' '); }); @@ -222,6 +269,10 @@ export default class Table extends SuperComponent { // 单元格完整类名(含列样式、固定列、合并单元格边框处理),供 template 直接使用 const tdClasses: string[] = [`${classPrefix}__td`, `${classPrefix}__td-${colIndex}`]; + // 选中列 + if ((col as PrimaryTableCol).type === 'multiple' || (col as PrimaryTableCol).type === 'single') { + tdClasses.push(`${classPrefix}__cell-check`); + } if (col.align && col.align !== 'left') tdClasses.push(`${prefix}-align-${col.align}`); if (col.fixed === 'left') tdClasses.push(`${classPrefix}__cell--fixed-left`); if (col.fixed === 'right') tdClasses.push(`${classPrefix}__cell--fixed-right`); @@ -232,10 +283,14 @@ export default class Table extends SuperComponent { tdClasses.push(getColumnClassName(col, { row, col, rowIndex, colIndex, type: 'td' })); let cellContent = ''; + let cellType = 'normal'; // normal | select if (col.colKey === 'serial-number') { cellContent = String(rowIndex + 1); + } else if ((col as PrimaryTableCol).type === 'multiple' || (col as PrimaryTableCol).type === 'single') { + // 选中列 + cellType = 'select'; } else if (typeof col.cell === 'function') { - cellContent = col.cell({ row, col, rowIndex, colIndex }); + cellContent = (col.cell as Function)({ row, col, rowIndex, colIndex }); } else { const val = get(row, col.colKey || ''); if (val !== undefined && val !== null && val !== '') { @@ -250,6 +305,32 @@ export default class Table extends SuperComponent { ? `grid-column: ${colIndex + 1} / span ${colspan || 1}; grid-row: ${rowIndex + 1} / span ${rowspan || 1}` : colStyles[colIndex]; + // 选中状态 + const rowId = get(row, rowKey || 'id'); + const isChecked = tSelectedRowKeys.includes(rowId); + // 半选状态:检查 indeterminateSelectedRowKeys 是否包含当前行 key + const isIndeterminate = indeterminateSelectedRowKeys?.includes(rowId) || false; + // 解析 checkProps(支持函数和对象形式) + const checkProps = (() => { + const colCheckProps = (col as PrimaryTableCol).checkProps; + if (!colCheckProps) return {}; + if (typeof colCheckProps === 'function') { + return colCheckProps({ row, rowIndex }) || {}; + } + return colCheckProps || {}; + })(); + // 解析列级 disabled(支持函数和布尔值) + const colDisabled = (() => { + const colDisable = (col as PrimaryTableCol).disabled; + if (!colDisable) return false; + if (typeof colDisable === 'function') { + return colDisable({ row, rowIndex }) || false; + } + return colDisable; + })(); + const allowUncheck = (checkProps as any).allowUncheck || false; + const isDisabled = colDisabled || checkProps.disabled || false; + return { colKey: col.colKey || String(colIndex), colIndex, @@ -257,6 +338,13 @@ export default class Table extends SuperComponent { tdClass: tdClasses.filter(Boolean).join(' '), cellStyle, skipped: skipped || false, + cellType, + columnType: (col as PrimaryTableCol).type || 'normal', + isChecked, + isDisabled, + isIndeterminate, + allowUncheck, + rowId, }; }); @@ -268,6 +356,10 @@ export default class Table extends SuperComponent { rowClass: (() => { const classes: string[] = []; const dataLen = data.length; + const rowId = get(row, rowKey || 'id'); + if (tSelectedRowKeys.includes(rowId)) { + classes.push(`${classPrefix}__row--selected`); + } if (fixedTopRows > 0 && rowIndex < fixedTopRows) { classes.push(`${classPrefix}__row--fixed-top`); } @@ -321,6 +413,33 @@ export default class Table extends SuperComponent { .filter(Boolean) .join(' '); + // 计算全选状态 + const selectCol = (columns || []).find((c: PrimaryTableCol) => c.type === 'multiple'); + let allChecked = false; + let isIndeterminateChecked = false; + let hasSelectableRows = false; + if (selectCol && (data || []).length > 0) { + const canSelectedRowKeys: any[] = []; + (data || []).forEach((row: TableRowData, rowIndex: number) => { + const isDisabled = this.getRowSelectDisabled(row, rowIndex, selectCol); + if (!isDisabled) { + canSelectedRowKeys.push(get(row, rowKey || 'id')); + } + }); + hasSelectableRows = canSelectedRowKeys.length > 0; + // 选中行与可选行的交集 + const intersectionKeys = canSelectedRowKeys.filter((key: any) => tSelectedRowKeys.includes(key)); + // 全选:所有可选行都被选中,且没有额外的选中行 + allChecked = + canSelectedRowKeys.length !== 0 && + intersectionKeys.length === canSelectedRowKeys.length && + intersectionKeys.length === tSelectedRowKeys.length; + // 半选:部分可选行被选中,或有不可见的选中行 + isIndeterminateChecked = + (intersectionKeys.length > 0 && intersectionKeys.length < canSelectedRowKeys.length) || + intersectionKeys.length < tSelectedRowKeys.length; + } + this.setData( { tableClasses, @@ -338,6 +457,9 @@ export default class Table extends SuperComponent { hasSpan, tbodyStyles, contentClasses, + allChecked, + isIndeterminateChecked, + hasSelectableRows, }, () => { // 动态测量行高,修正固定行的 top/bottom 值 @@ -394,18 +516,28 @@ export default class Table extends SuperComponent { onRowClick(this: any, e: any) { const { rowIndex } = e.currentTarget.dataset; - const { data } = this.properties; + const { data, columns, selectOnRowClick } = this.properties; if (data && data[rowIndex]) { this.triggerEvent('row-click', { row: data[rowIndex], index: rowIndex, }); + if (selectOnRowClick) { + const selectCol = (columns || []).find((c: PrimaryTableCol) => c.type === 'multiple' || c.type === 'single'); + if (selectCol) { + const row = data[rowIndex]; + const isDisabled = this.getRowSelectDisabled(row, rowIndex, selectCol); + if (!isDisabled) { + this.onSelectChange({ currentTarget: { dataset: { rowIndex } } }); + } + } + } } }, onCellClick(this: any, e: any) { const { rowIndex, colIndex } = e.currentTarget.dataset; - const { data, columns } = this.properties; + const { data, columns, selectOnRowClick } = this.properties; if (data && data[rowIndex] && columns && columns[colIndex]) { this.triggerEvent('cell-click', { row: data[rowIndex], @@ -420,7 +552,138 @@ export default class Table extends SuperComponent { row: data[rowIndex], index: rowIndex, }); + // 合并场景也需要处理行点击选中 + if (selectOnRowClick) { + const selectCol = (columns || []).find((c: PrimaryTableCol) => c.type === 'multiple' || c.type === 'single'); + if (selectCol) { + const row = data[rowIndex]; + const isDisabled = this.getRowSelectDisabled(row, rowIndex, selectCol); + if (!isDisabled) { + this.onSelectChange({ currentTarget: { dataset: { rowIndex } } }); + } + } + } + } + }, + + /** 获取行选中禁用状态 */ + getRowSelectDisabled(this: any, row: any, rowIndex: number, col: any) { + // 列级 disabled + const colDisabled = (() => { + const colDisable = col?.disabled; + if (!colDisable) return false; + if (typeof colDisable === 'function') { + return colDisable({ row, rowIndex }) || false; + } + return colDisable; + })(); + // checkProps.disabled + const checkProps = (() => { + const colCheckProps = col?.checkProps; + if (!colCheckProps) return {}; + if (typeof colCheckProps === 'function') { + return colCheckProps({ row, rowIndex }) || {}; + } + return colCheckProps || {}; + })(); + return colDisabled || checkProps.disabled || false; + }, + + /** 选中行切换 */ + onSelectChange(this: any, e: any) { + const { rowIndex } = e.currentTarget.dataset; + const { data, rowKey, columns } = this.properties; + const { innerSelectedRowKeys, renderData } = this.data; + const row = data && data[rowIndex]; + if (!row) return; + const rowId = get(row, rowKey || 'id'); + let newKeys = [...innerSelectedRowKeys]; + const existIndex = newKeys.indexOf(rowId); + + // 判断是单选还是多选列 + const selectCol = (columns || []).find((c: PrimaryTableCol) => c.type === 'multiple' || c.type === 'single'); + if (!selectCol) return; + + // 从 renderData 获取当前行的 allowUncheck + const currentRowData = renderData?.find((r: any) => r.rowIndex === rowIndex); + const allowUncheck = currentRowData?.cells?.find((c: any) => c.columnType === 'single')?.allowUncheck || false; + + if (selectCol.type === 'multiple') { + if (existIndex !== -1) { + newKeys.splice(existIndex, 1); + } else { + newKeys.push(rowId); + } + } else if (selectCol.type === 'single') { + if (existIndex !== -1 && allowUncheck) { + newKeys = []; + } else { + newKeys = [rowId]; + } } + + // 更新内部状态 + this.setData({ innerSelectedRowKeys: newKeys }); + + // 获取选中的行数据 + const selectedRowData = newKeys + .map((key: any) => (data as any[]).find((d) => get(d, rowKey || 'id') === key)) + .filter(Boolean); + + // 触发事件 + this.triggerEvent('select-change', { + selectedRowKeys: newKeys, + selectedRowData, + currentRowKey: rowId, + currentRowData: row, + type: existIndex !== -1 ? 'uncheck' : 'check', + }); + + this.updateTable(); + }, + + /** 全选/取消全选 */ + onSelectAll(this: any) { + const { data, rowKey, columns, reserveSelectedRowOnPaginate } = this.properties; + const { innerSelectedRowKeys, allChecked } = this.data; + const selectCol = (columns || []).find((c: PrimaryTableCol) => c.type === 'multiple'); + + const canSelectedRowKeys: any[] = []; + (data || []).forEach((row: TableRowData, rowIndex: number) => { + const isDisabled = this.getRowSelectDisabled(row, rowIndex, selectCol); + if (!isDisabled) { + canSelectedRowKeys.push(get(row, rowKey || 'id')); + } + }); + + const disabledSelectedRowKeys = (innerSelectedRowKeys || []).filter( + (id: any) => !canSelectedRowKeys.includes(id), + ); + + let newKeys: any[]; + if (allChecked) { + newKeys = [...disabledSelectedRowKeys]; + } else if (reserveSelectedRowOnPaginate === false) { + newKeys = [...disabledSelectedRowKeys, ...canSelectedRowKeys]; + } else { + newKeys = [...new Set([...disabledSelectedRowKeys, ...innerSelectedRowKeys, ...canSelectedRowKeys])]; + } + + this.setData({ innerSelectedRowKeys: newKeys }); + + // 获取选中的行数据 + const selectedRowData = newKeys + .map((key: any) => (data as any[]).find((d) => get(d, rowKey || 'id') === key)) + .filter(Boolean); + + this.triggerEvent('select-change', { + selectedRowKeys: newKeys, + selectedRowData, + currentRowKey: 'CHECK_ALL_BOX', + type: allChecked ? 'uncheck' : 'check', + }); + + this.updateTable(); }, onScroll(this: any, e: any) { diff --git a/packages/components/table/table.wxml b/packages/components/table/table.wxml index 2fa0f239c9..e3799f5765 100644 --- a/packages/components/table/table.wxml +++ b/packages/components/table/table.wxml @@ -9,7 +9,31 @@ data-col-index="{{cell.colIndex}}" bind:tap="onCellClick" > - {{cell.content}} + + + + + + + + + + {{cell.content}} @@ -33,7 +57,22 @@ class="{{classPrefix}}__th {{thClassNames[colIndex]}}" style="{{colStyles[colIndex]}}" > - {{col.title}} + + + {{col.title}} + + + + + + {{col.title}} diff --git a/packages/components/table/type.ts b/packages/components/table/type.ts index e639e93115..4f40fa59c5 100644 --- a/packages/components/table/type.ts +++ b/packages/components/table/type.ts @@ -5,7 +5,11 @@ * */ import { LoadingProps } from '../loading/index'; -import type { ClassName } from '../common/common'; +import { CheckboxProps } from '../checkbox/index'; +import { RadioProps } from '../radio/index'; +import { PopupProps } from '../popup/index'; +import { InputProps } from '../input/index'; +import type { OptionData, ClassName, Styles, HTMLElementAttributes } from '../common/common'; export interface TdBaseTableProps { /** @@ -75,6 +79,14 @@ export interface TdBaseTableProps { type: BooleanConstructor; value?: boolean; }; + /** + * 数据加载模式 + * @default pull-refresh + */ + loadingMode?: { + type: StringConstructor; + value?: 'pull-refresh' | 'pagination'; + }; /** * 透传加载组件全部属性 */ @@ -89,6 +101,27 @@ export interface TdBaseTableProps { type: null; value?: string | number; }; + /** + * 分页配置,值为空则不显示。具体 API 参考分页组件。当 `data` 数据长度超过分页大小时,会自动对本地数据 `data` 进行排序,如果不希望对于 `data` 进行排序,可以设置 `disableDataPage = true` + */ + pagination?: { + type: ObjectConstructor; + value?: PaginationProps; + }; + /** + * HTML 标签 `tr` 的属性。类型为 Function 时,参数说明:`params.row` 表示行数据;`params.rowIndex` 表示行下标;`params.type=body` 表示属性作用于 `tbody` 中的元素;`params.type=foot` 表示属性作用于 `tfoot` 中的元素。
示例一:{ draggable: true },
示例二:[{ draggable: true }, { title: '超出省略显示' }]。
示例三:() => [{ draggable: true }] + */ + rowAttributes?: { + type: null; + value?: TableRowAttributes; + }; + /** + * 行类名,泛型 T 指表格数据类型。`params.row` 表示行数据;`params.rowIndex` 表示行下标;`params.type=body` 表示类名作用于 `tbody` 中的元素;`params.type= tfoot` 表示类名作用于 `tfoot` 中的元素 + */ + rowClassName?: { + type: null; + value?: ClassName | ((params: RowClassNameParams) => ClassName); + }; /** * 唯一标识一行数据的字段名,来源于 `data` 中的字段。如果是字段嵌套多层,可以设置形如 `item.a.id` 的方法 * @default 'id' @@ -166,6 +199,15 @@ export interface BaseTableCol { * @default '' */ colKey?: string; + /** + * 单元格和表头内容超出时,是否显示省略号。如果仅希望单元格超出省略,可设置 `ellipsisTitle = false`。
值为 `true`,则超出省略浮层默认显示单元格内容;
值类型为 `Function` 则自定义超出省略浮中层显示的内容。
请注意单元格超出省略的两个基本点:1. 内容元素是内联元素或样式(自定义单元格内容时需特别注意);2. 内容超出父元素 + * @default false + */ + ellipsis?: boolean; + /** + * 表头内容超出时,是否显示省略号。优先级高于 `ellipsis`。
值为 `true`,则超出省略的浮层默认显示表头全部内容;
值类型为 `Function` 用于自定义超出省略浮层显示的表头内容 + */ + ellipsisTitle?: boolean; /** * 固定列显示位置 * @default left @@ -175,12 +217,319 @@ export interface BaseTableCol { * 透传 CSS 属性 `min-width` 到 `` 元素。⚠️ 仅少部分浏览器支持,如:使用 [TablesNG](https://docs.google.com/document/d/16PFD1GtMI9Zgwu0jtPaKZJ75Q2wyZ9EZnVbBacOfiNA/preview) 渲染的 Chrome 浏览器支持 `minWidth` */ minWidth?: string | number; + /** + * 自定义表头渲染,优先级高于 render + * @default '' + */ + title?: string; /** * 列宽,可以作为最小宽度使用。当列宽总和小于 `table` 元素时,浏览器根据宽度设置情况自动分配宽度;当列宽总和大于 `table` 元素,表现为定宽。可以同时调整 `table` 元素的宽度来达到自己想要的效果 */ width?: string | number; } +export interface TdPrimaryTableProps { + /** + * 列配置,泛型 T 指表格数据类型 + * @default [] + */ + columns?: { + type: ArrayConstructor; + value?: Array>; + }; + /** + * 列配置功能中,当前显示的列 + */ + displayColumns?: { + type: ArrayConstructor; + value?: CheckboxGroupValue; + }; + /** + * 列配置功能中,当前显示的列,非受控属性 + */ + defaultDisplayColumns?: { + type: ArrayConstructor; + value?: CheckboxGroupValue; + }; + /** + * 拖拽排序方式,值为 `row` 表示行拖拽排序,这种方式无法进行文本复制,慎用。值为`row-handler` 表示通过拖拽手柄进行行拖拽排序。值为 `col` 表示列顺序拖拽。值为 `row-handler-col` 表示同时支持行拖拽和列拖拽。⚠️`drag-col` 已废弃,请勿使用 + */ + dragSort?: { + type: StringConstructor; + value?: 'row' | 'row-handler' | 'col' | 'row-handler-col' | 'drag-col'; + }; + /** + * 拖拽排序扩展参数,具体参数见 [Sortable](https://github.com/SortableJS/Sortable) + */ + // dragSortOptions?: { + // type: ObjectConstructor; + // value?: SortableOptions; + // }; + /** + * 用于控制是否显示「展开图标列」,值为 `false` 则不会显示。可以精确到某一行是否显示,还可以自定义展开图标内容。`expandedRow` 存在时,该参数有效。支持全局配置 `GlobalConfigProvider` + * @default true + */ + expandIcon?: { + type: BooleanConstructor; + value?: boolean; + }; + /** + * 是否允许点击行展开 + */ + expandOnRowClick?: { + type: BooleanConstructor; + value?: boolean; + }; + /** + * 展开行 + * @default [] + */ + expandedRowKeys?: { + type: ArrayConstructor; + value?: Array; + }; + /** + * 展开行,非受控属性 + * @default [] + */ + defaultExpandedRowKeys?: { + type: ArrayConstructor; + value?: Array; + }; + /** + * 自定义过滤状态行及清空筛选等 + */ + filterRow?: { + type: StringConstructor; + value?: string; + }; + /** + * 过滤数据的值 + */ + filterValue?: { + type: ObjectConstructor; + value?: FilterValue; + }; + /** + * 过滤数据的值,非受控属性 + */ + defaultFilterValue?: { + type: ObjectConstructor; + value?: FilterValue; + }; + /** + * 隐藏排序文本提示,支持全局配置 `GlobalConfigProvider`,默认全局配置值为 `false` + */ + hideSortTips?: { + type: BooleanConstructor; + value?: boolean; + }; + /** + * 半选状态行。选中行请更为使用 `selectedRowKeys` 控制 + */ + indeterminateSelectedRowKeys?: { + type: ArrayConstructor; + value?: Array; + }; + /** + * 是否支持多列排序 + * @default false + */ + multipleSort?: { + type: BooleanConstructor; + value?: boolean; + }; + /** + * 行选中功能,是否在分页时保留上一页选中结果不清空。分页场景下,会全选所有页数据,保留跨分页数据。值为 `false` 则表示全部选中操作停留在当前页,不跨分页。 + * @default true + */ + reserveSelectedRowOnPaginate?: { + type: BooleanConstructor; + value?: boolean; + }; + /** + * 是否在点击整行时选中 + */ + selectOnRowClick?: { + type: BooleanConstructor; + value?: boolean; + }; + /** + * 选中行。半选状态行请更为使用 `indeterminateSelectedRowKeys` 控制 + * @default [] + */ + selectedRowKeys?: { + type: ArrayConstructor; + value?: Array; + }; + /** + * 选中行。半选状态行请更为使用 `indeterminateSelectedRowKeys` 控制,非受控属性 + * @default [] + */ + defaultSelectedRowKeys?: { + type: ArrayConstructor; + value?: Array; + }; + /** + * 当前排序列是否显示背景色 + * @default false + */ + showSortColumnBgColor?: { + type: BooleanConstructor; + value?: boolean; + }; + /** + * 排序控制。sortBy 排序字段;descending 是否进行降序排列。值为数组时,表示正进行多字段排序 + */ + sort?: { + type: null; + value?: TableSort; + }; + /** + * 排序控制。sortBy 排序字段;descending 是否进行降序排列。值为数组时,表示正进行多字段排序,非受控属性 + */ + defaultSort?: { + type: null; + value?: TableSort; + }; +} + +export interface PrimaryTableCol { + /** + * 透传参数,`colKey` 值为 `row-select` 时,配置有效。具体定义参考 Checkbox 组件 和 Radio 组件。泛型 T 指表格数据类型 + */ + checkProps?: CheckProps; + /** + * 用于多级表头,泛型 T 指表格数据类型 + */ + children?: Array>; + /** + * 渲染列所需字段,必须唯一。值为 `row-select` 表示当前列为行选中操作列。值为 `drag` 表示当前列为拖拽排序操作列。值为 `serial-number` 表示当前列为「序号」列 + * @default '' + */ + colKey?: string; + /** + * 是否禁用行选中,`colKey` 值为 `row-select` 时,配置有效 + */ + disabled?: (options: { row: T; rowIndex: number }) => boolean; + /** + * 过滤规则,支持多选(multiple)、单选(single)、输入框(input) 等三种形式。想要自定义过滤组件,可通过 `filter.component` 实现,自定义过滤组件需要包含参数 value 和事件 change。更多信息请查看当前页面中 `TableColumnFilter` 的详细文档 + */ + filter?: TableColumnFilter; + /** + * 当前列支持排序的方式,desc 表示当前列只能进行降序排列;asc 表示当前列只能进行升序排列;all 表示当前列既可升序排列,又可以降序排列 + * @default all + */ + sortType?: SortType; + /** + * 该列是否支持排序。值为 true 表示该列支持排序;值类型为函数,表示对本地数据 `data` 进行排序,返回值参考 [MDN Array.sort](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)。泛型 T 指表格数据类型 + * @default false + */ + sorter?: boolean | SorterFun; + /** + * 自定义表头渲染。值类型为 string 表示使用插槽渲染,插槽名称为 title 的值。优先级高于 render + * @default '' + */ + title?: string; + /** + * `colKey` 值为 `row-select` 时表示行选中列,有两种模式:单选和多选。 `type=single` 表示单选,`type=multiple` 表示多选 + * @default single + */ + type?: 'single' | 'multiple'; +} + +export interface TableColumnFilter { + /** + * 用于透传筛选器属性到自定义组件 `component`,HTML 原生属性 + */ + attrs?: HTMLElementAttributes; + /** + * 透传类名到自定义组件 `component` + * @default '' + */ + classNames?: ClassName; + /** + * 哪些事件触发后会进行过滤搜索(确认按钮无需配置,会默认触发搜索)。输入框组件示例:`confirmEvents: ['onEnter']` + */ + confirmEvents?: string[]; + /** + * 过滤项标题文本,显示在“过滤结果行”中的列标题描述。一般用于表头标题和过滤文本行中的列标题不一样的场景 + */ + label?: string; + /** + * 用于配置当前筛选器可选值有哪些,仅当 `filter.type` 等于 `single` 或 `multiple` 时有效 + */ + list?: Array; + /** + * 透传 Popup 组件全部属性到筛选器浮层 + */ + popupProps?: PopupProps; + /** + * 用于透传筛选器属性到自定义组件 `component`,可以对筛选器进行任何原组件支持的属性配置 + */ + props?: FilterProps; + /** + * 重置时设置的值,示例:'' 或 [] + */ + resetValue?: any; + /** + * 是否显示重置和确认。值为真,过滤事件(filter-change)会在确定时触发;值为假,则数据变化时会立即触发过滤事件 + * @default false + */ + showConfirmAndReset?: boolean; + /** + * 透传内联样式到自定义组件 `component` + */ + style?: Styles; + /** + * 用于设置筛选器类型:单选按钮筛选器、复选框筛选器、输入框筛选器。更多复杂组件,请更为使用 `component` 自定义任意组件 + * @default '' + */ + type?: FilterType; +} + +export interface PaginationProps { + current?: number; + defaultCurrent?: number; + disabled?: boolean; + foldedMaxPageBtn?: number; + maxPageBtn?: number; + pageEllipsisMode?: 'mid' | 'both-ends'; + pageSize?: number; + defaultPageSize?: number; + pageSizeOptions?: Array; + showFirstAndLastPageBtn?: boolean; + showJumper?: boolean; + showPageNumber?: boolean; + showPageSize?: boolean; + showPreviousAndNextBtn?: boolean; + size?: 'small' | 'medium'; + theme?: 'default' | 'simple'; + total?: number; + totalContent?: string; + onChange?: (pageInfo: PageInfo) => void; + onCurrentChange?: (current: number, pageInfo: PageInfo) => void; + onPageSizeChange?: (pageSize: number, pageInfo: PageInfo) => void; +} + +export interface PageInfo { + current: number; + previous: number; + pageSize: number; +} + +export type TableRowAttributes = + | HTMLElementAttributes + | ((params: { row: T; rowIndex: number; type: 'body' | 'foot' }) => HTMLElementAttributes) + | Array>; + +export interface RowClassNameParams { + row: T; + rowIndex: number; + rowKey?: string; + type?: 'body' | 'foot'; +} + export type TableRowspanAndColspanFunc = ( params: BaseTableCellParams, ) => RowspanColspan; @@ -209,4 +558,42 @@ export interface CellData extends BaseTab type: 'th' | 'td'; } +export interface BaseTableColParams { + col: BaseTableCol; + colIndex: number; +} + export type DataType = TableRowData; + +export type CheckboxGroupValue = Array; + +export interface ExpandArrowRenderParams { + row: T; + index: number; +} + +export interface TableExpandedRowParams { + row: T; + index: number; + columns: PrimaryTableCol[] | BaseTableCol[]; +} + +export type FilterValue = { [key: string]: any }; + +export type TableSort = SortInfo | Array; + +export interface SortInfo { + sortBy: string; + descending: boolean; +} + +export type CheckProps = + CheckboxProps | RadioProps | ((options: { row: T; rowIndex: number }) => CheckboxProps | RadioProps); + +export type SortType = 'desc' | 'asc' | 'all'; + +export type SorterFun = (a: T, b: T) => number; + +export type FilterProps = RadioProps | CheckboxProps | InputProps | { [key: string]: any }; + +export type FilterType = 'input' | 'single' | 'multiple';