Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(pro:table): add dnd sortable support for proTable #1957

Merged
merged 1 commit into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions packages/components/table/src/main/body/Body.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ import { TABLE_TOKEN } from '../../token'

export default defineComponent({
setup(_, { slots }) {
const { mergedPrefixCls } = inject(TABLE_TOKEN)!
const { props, mergedPrefixCls } = inject(TABLE_TOKEN)!

return () => {
return <tbody class={`${mergedPrefixCls.value}-tbody`}>{slots.default?.()}</tbody>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const Tag = (props.customTag?.body ?? 'tbody') as any

return <Tag class={`${mergedPrefixCls.value}-tbody`}>{slots.default?.()}</Tag>
}
},
})
1 change: 1 addition & 0 deletions packages/components/table/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ export interface TableCustomAdditional<T = any, K = VKey> {
}

export interface TableCustomTag {
body?: string | Component
bodyCell?: string | Component
bodyRow?: string | Component
head?: string | Component
Expand Down
14 changes: 14 additions & 0 deletions packages/pro/table/demo/DndSortable.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
order: 21
title:
zh: 拖拽排序
en: Dnd sortable
---

## zh

通过 `dndSortable` 配置开启拖拽排序。

## en

enable drag sorting with `dndSortable` prop.
100 changes: 100 additions & 0 deletions packages/pro/table/demo/DndSortable.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<template>
<div style="height: 500px">
<IxProTable
autoHeight
:columns="columns"
:dataSource="dataSource"
header="Pro Table"
dndSortable
virtual
:pagination="false"
:layoutTool="{ searchable: true }"
:toolbar="toolbar"
@columnsChange="onColumnsChange"
@dndSortChange="onSortChange"
@dndSortReorder="console.log"
>
<template #name="{ value }">
<a>{{ value }}</a>
</template>
<template #action="{ record }">
<a style="margin-right: 8px">Invite {{ record.name }}</a>
<a>Delete</a>
</template>
</IxProTable>
</div>
</template>

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

import { IxButton } from '@idux/components/button'
import { ProTableColumn } from '@idux/pro/table'

interface Data {
key: number
name: string
age: number
address: string
description: string
}

const toolbar = [
h(IxButton, { size: 'xs' }, () => 'Load'),
h(IxButton, { icon: 'reload', size: 'xs', title: 'reload', onClick: () => console.log('reload data') }),
]

const onColumnsChange = console.log

const columns: ProTableColumn<Data>[] = [
{
type: 'selectable',
},
{
type: 'indexable',
layoutable: false,
},
{
title: 'Name',
dataKey: 'name',
changeFixed: false,
customCell: 'name',
},
{
title: 'Age',
dataKey: 'age',
changeFixed: false,
},
{
title: 'Address',
dataKey: 'address',
changeFixed: false,
},
{
title: 'Action',
key: 'action',
changeIndex: false,
customCell: 'action',
},
]

const data: Data[] = []
for (let index = 0; index < 100; index++) {
data.push({
key: index,
name: `Edrward ${index}`,
age: 18 + (index % 10),
address: `London Park no. ${index}`,
description: `My name is Edrward ${index}, I am ${
18 + (index % 10)
} years old, living in London Park no. ${index}.`,
})
}

const dataSource = ref(data)

const onSortChange = (newData: Data[]) => {
console.log('onSortChange', newData)
dataSource.value = newData
}
</script>
26 changes: 26 additions & 0 deletions packages/pro/table/docs/Api.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,33 @@
| `columns` | 表格列的配置描述 | `ProTableColumn[]` | - | - | 参见[ProTableColumn](#ProTableColumn) |
| `layoutTool` | 是否显示布局设置工具按钮 | `boolean \| ProTableLayoutToolProps` | `true` | - | 当设置为 `false` 时,你也可以使用 `IxProTableLayoutTool` 来自定义它的位置和展示形式 |
| `toolbar` | 表格的工具栏 | `VNode[] \| #toolbar` | - | - | - |
| `dndSortable` | 拖拽排序配置 | `boolean \| ProTableDataDndSortable` | `false` | - | - |
| `onColumnsChange` | 表格列的配置发生改变后的回调 | `(columns: ProTableColumn[]) => void` | - | - | - |
| `onDndSortReorder` | 表格数据重排序之后的回调 | `(reorderInfo: DndSortableReorderInfo) => void` | - | - | - |
| `onDndSortChange` | 表格数据排序改变之后的回调 | `(newData: any[], oldData: any[]) => void` | - | - | - |

```ts
export interface DndSortableReorderInfo {
sourceIndex: number
targetIndex: number
sourceKey: VKey
targetKey: VKey
sourceData: any
targetData: any
operation: 'insertBefore' | 'insertAfter' | 'insertChild'
}
```

```ts
export interface ProTableDataDndSortable extends DndSortable {
autoScroll?: boolean // 表格体是否随着拖拽自动滚动
isSticky?: boolean | ((options: DndSortableIsStickyOptions) => boolean) // 拖拽离开目标元素后是否保持拖拽状态
canDrag?: boolean | ((options: CanDragOptions) => boolean) // 是否可拖拽
canDrop?: boolean | ((options: CanDropOptions) => boolean) // 是否可拖拽放置
dragHandleColumn?: Boolean | VKey // 配置拖拽把手的列,默认为true,配置具体的key,可以在columns中自定义该列
dragHandleIcon?: string // 拖拽把手的图标
}
```

更多属性请参考 [TableProps](/components/table/zh#TableProps).

Expand Down
1 change: 1 addition & 0 deletions packages/pro/table/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ export type {
ProTableColumnExpandable,
ProTableColumnSelectable,
ProTableColumnIndexable,
ProTableDataDndSortable,
} from './src/types'
46 changes: 43 additions & 3 deletions packages/pro/table/src/ProTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@ import { IxButtonGroup } from '@idux/components/button'
import { useGlobalConfig as useComponentsGlobalConfig } from '@idux/components/config'
import { IxHeader } from '@idux/components/header'
import { IxTable, type TableCustomAdditional, type TableCustomTag, type TableInstance } from '@idux/components/table'
import { useGetKey } from '@idux/components/utils'
import { useGlobalConfig } from '@idux/pro/config'

import ProTableLayoutTool from './ProTableLayoutTool'
import { useColumns } from './composables/useColumns'
import { useResizable } from './composables/useResizable'
import ResizableHeadCell from './contents/ResizableHeadCell'
import SortableBody from './contents/SortableBody'
import SortableBodyRow from './contents/SortableBodyRow'
import { proTableToken } from './token'
import { proTableProps } from './types'
import { type ResolvedProTableDataDndSortable, proTableProps } from './types'

export default defineComponent({
name: 'IxProTable',
Expand All @@ -36,7 +39,25 @@ export default defineComponent({
const locale = useGlobalConfig('locale')

const mergedPrefixCls = computed(() => `${common.prefixCls}-table`)
const columnsContext = useColumns(props, config)
const mergedDndSortable = computed<ResolvedProTableDataDndSortable | false>(() => {
if (!props.dndSortable) {
return false
}

const { autoScroll, canDrag, canDrop, dragHandleColumn, dragHandleIcon, isSticky } =
props.dndSortable === true ? ({} as ResolvedProTableDataDndSortable) : props.dndSortable

return {
autoScroll: autoScroll ?? true,
dragHandleColumn: dragHandleColumn ?? true,
dragHandleIcon: dragHandleIcon ?? 'holder',
isSticky: isSticky ?? true,
canDrag,
canDrop,
}
})
const mergedGetKey = useGetKey(props, baseConfig, 'pro/table')
const columnsContext = useColumns(props, config, slots, mergedPrefixCls, mergedDndSortable)
const { hasResizable, onResizeEnd } = useResizable(columnsContext)
const mergedConfigSize = computed(() => props.size ?? baseConfig.size)
const [mergedSize, setMergedSize] = useState(mergedConfigSize.value)
Expand All @@ -48,6 +69,8 @@ export default defineComponent({
locale,
mergedPrefixCls,
mergedSize,
mergedDndSortable,
mergedGetKey,
setMergedSize,
...columnsContext,
})
Expand Down Expand Up @@ -96,7 +119,16 @@ export default defineComponent({
}

return () => {
const { customAdditional, customTag, layoutTool, toolbar, tableLayout, ...restProps } = props
const {
customAdditional,
customTag,
layoutTool,
toolbar,
tableLayout,
dndSortable,
columnDndSortable,
...restProps
} = props
const resizable = hasResizable.value
const mergedTableLayout = tableLayout ? tableLayout : resizable ? 'fixed' : undefined

Expand All @@ -106,9 +138,17 @@ export default defineComponent({
const additionalProps = customAdditional?.headCell ? customAdditional.headCell({ column }) : undefined
return resizable ? { ...additionalProps, column, onResizeEnd } : additionalProps
},
bodyRow: data => {
const additionalProps = customAdditional?.bodyRow ? customAdditional.bodyRow(data) : undefined
return mergedDndSortable.value
? { ...additionalProps, itemKey: mergedGetKey.value(data.record) }
: additionalProps
},
}
const mergedCustomTag: TableCustomTag = {
headCell: resizable ? ResizableHeadCell : undefined,
body: mergedDndSortable.value ? SortableBody : undefined,
bodyRow: mergedDndSortable.value ? SortableBodyRow : undefined,
...customTag,
}

Expand Down
Loading