From a715dfd5456a1ab6b4e33c112477edd355832921 Mon Sep 17 00:00:00 2001 From: doom-9 <65016011+doom-9@users.noreply.github.com> Date: Fri, 3 Sep 2021 01:00:20 +0800 Subject: [PATCH] feat(data-table): support shiftKey check (#1026) * feat:n-input Support hidden password * feat(form): support require-mark-placement(#171) * Revert "feat(form): support require-mark-placement(#171)" This reverts commit 06277776933ed4e68b32d2651014458aca2e50f6. * Revert "feat:n-input Support hidden password" This reverts commit ea6491783dcc79e610534632a05b2894ded97494. * feat(data-table): wip * feat: fix code * feat: fix code * feat: update changelog * feat: update changelog * feat: fix code * feat: fix code --- CHANGELOG.en-US.md | 1 + CHANGELOG.zh-CN.md | 1 + src/checkbox/src/Checkbox.tsx | 23 +++++++---- src/data-table/src/TableParts/Body.tsx | 39 +++++++++++++++++-- .../src/TableParts/BodyCheckbox.tsx | 4 +- src/data-table/src/interface.ts | 4 +- src/data-table/src/use-check.ts | 4 +- 7 files changed, 60 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index 4503e5ccd41..6eae4c2578c 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -16,6 +16,7 @@ - `n-tree` & `n-tree-select` add `label-field` prop. - `n-tree` & `n-tree-select` add `children-field` prop. - `n-dropdown` option add `props` prop, closes [#813](https://github.com/TuSimple/naive-ui/issues/813). +- `n-data-table` supports multi-selection by holding down `shift`, closes [#554](https://github.com/TuSimple/naive-ui/issues/554). ### Fixes diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index bb4c4df4b46..e789b99cfd1 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -16,6 +16,7 @@ - `n-tree` 和 `n-tree-select` 新增 `label-field` 属性 - `n-tree` 和 `n-tree-select` 新增 `children-field` 属性 - `n-dropdown` 选项新增 `props` 属性,关闭 [#813](https://github.com/TuSimple/naive-ui/issues/813) +- `n-data-table` 支持按住 `shift` 进行多选操作,关闭 [#554](https://github.com/TuSimple/naive-ui/issues/554) ### Fixes diff --git a/src/checkbox/src/Checkbox.tsx b/src/checkbox/src/Checkbox.tsx index ebfbef49e2e..b817b092b65 100644 --- a/src/checkbox/src/Checkbox.tsx +++ b/src/checkbox/src/Checkbox.tsx @@ -48,10 +48,10 @@ const checkboxProps = { }, // eslint-disable-next-line vue/prop-name-casing 'onUpdate:checked': [Function, Array] as PropType< - MaybeArray<(value: boolean) => void> + MaybeArray<(value: boolean, e: MouseEvent | KeyboardEvent) => void> >, onUpdateChecked: [Function, Array] as PropType< - MaybeArray<(value: boolean) => void> + MaybeArray<(value: boolean, e: MouseEvent | KeyboardEvent) => void> >, // private privateTableHeader: Boolean, @@ -154,7 +154,7 @@ export default defineComponent({ props, mergedClsPrefixRef ) - function toggle (): void { + function toggle (e: MouseEvent | KeyboardEvent): void { if (NCheckboxGroup && props.value !== undefined) { NCheckboxGroup.toggleCheckbox(!renderedCheckedRef.value, props.value) } else { @@ -165,17 +165,17 @@ export default defineComponent({ } = props const { nTriggerFormInput, nTriggerFormChange } = formItem const nextChecked = !renderedCheckedRef.value - if (_onUpdateCheck) call(_onUpdateCheck, nextChecked) - if (onUpdateChecked) call(onUpdateChecked, nextChecked) + if (_onUpdateCheck) call(_onUpdateCheck, nextChecked, e) + if (onUpdateChecked) call(onUpdateChecked, nextChecked, e) if (onChange) call(onChange, nextChecked) // deprecated nTriggerFormInput() nTriggerFormChange() uncontrolledCheckedRef.value = nextChecked } } - function handleClick (): void { + function handleClick (e: MouseEvent): void { if (!mergedDisabledRef.value) { - toggle() + toggle(e) } } function handleKeyUp (e: KeyboardEvent): void { @@ -184,7 +184,7 @@ export default defineComponent({ case 'Space': case 'Enter': case 'NumpadEnter': - toggle() + toggle(e) } } function handleKeyDown (e: KeyboardEvent): void { @@ -289,6 +289,13 @@ export default defineComponent({ onKeyup={handleKeyUp} onKeydown={handleKeyDown} onClick={handleClick} + onMousedown={() => { + const userCallBack = window.onselectstart + window.onselectstart = () => false + setTimeout(() => { + window.onselectstart = userCallBack + }, 0) + }} >
diff --git a/src/data-table/src/TableParts/Body.tsx b/src/data-table/src/TableParts/Body.tsx index 7fa55c0161d..35d426f975e 100644 --- a/src/data-table/src/TableParts/Body.tsx +++ b/src/data-table/src/TableParts/Body.tsx @@ -137,10 +137,39 @@ export default defineComponent({ } = inject(dataTableInjectionKey)! const scrollbarInstRef = ref(null) const virtualListRef = ref(null) + let lastSelectedKey: string | number = '' function handleCheckboxUpdateChecked ( tmNode: { key: RowKey }, - checked: boolean + checked: boolean, + shiftKey: boolean ): void { + const lastKey = lastSelectedKey + lastSelectedKey = tmNode.key + + if (shiftKey) { + const lastIndex = paginatedDataRef.value.findIndex( + (item) => item.key === lastKey + ) + if (lastIndex !== -1) { + const currentIndex = paginatedDataRef.value.findIndex( + (item) => item.key === tmNode.key + ) + const start = Math.min(lastIndex, currentIndex) + const end = Math.max(lastIndex, currentIndex) + const rowKeysToCheck: RowKey[] = [] + paginatedDataRef.value.slice(start, end + 1).forEach((r) => { + if (!r.disabled) { + rowKeysToCheck.push(r.key) + } + }) + if (checked) { + doCheck(rowKeysToCheck) + } else { + doUncheck(rowKeysToCheck) + } + } + } + if (checked) { doCheck(tmNode.key) } else { @@ -527,8 +556,12 @@ export default defineComponent({ key={currentPage} rowKey={rowKey} disabled={rowInfo.disabled} - onUpdateChecked={(checked) => - handleCheckboxUpdateChecked(rowInfo, checked) + onUpdateChecked={(checked: boolean, e) => + handleCheckboxUpdateChecked( + rowInfo, + checked, + e.shiftKey + ) } /> ) : null diff --git a/src/data-table/src/TableParts/BodyCheckbox.tsx b/src/data-table/src/TableParts/BodyCheckbox.tsx index b35a62748a5..191a4afe256 100644 --- a/src/data-table/src/TableParts/BodyCheckbox.tsx +++ b/src/data-table/src/TableParts/BodyCheckbox.tsx @@ -15,7 +15,9 @@ export default defineComponent({ required: true }, onUpdateChecked: { - type: Function as PropType<(checked: boolean) => void>, + type: Function as PropType< + (checked: boolean, e: MouseEvent | KeyboardEvent) => void + >, required: true } }, diff --git a/src/data-table/src/interface.ts b/src/data-table/src/interface.ts index 72ba074a45f..74898b1bf25 100644 --- a/src/data-table/src/interface.ts +++ b/src/data-table/src/interface.ts @@ -204,8 +204,8 @@ export interface DataTableInjection { doUpdateSorter: (sorter: SortState | null) => void doUncheckAll: (checkWholeTable?: boolean) => void doCheckAll: (checkWholeTable?: boolean) => void - doCheck: (rowKey: RowKey) => void - doUncheck: (rowKey: RowKey) => void + doCheck: (rowKey: RowKey | RowKey[]) => void + doUncheck: (rowKey: RowKey | RowKey[]) => void handleTableHeaderScroll: (e: Event) => void handleTableBodyScroll: (e: Event) => void syncScrollState: (deltaX?: number, deltaY?: number) => void diff --git a/src/data-table/src/use-check.ts b/src/data-table/src/use-check.ts index bd675023c5c..2148b99322f 100644 --- a/src/data-table/src/use-check.ts +++ b/src/data-table/src/use-check.ts @@ -88,14 +88,14 @@ export function useCheck ( if (onCheckedRowKeysChange) call(onCheckedRowKeysChange, keys) uncontrolledCheckedRowKeysRef.value = keys } - function doCheck (rowKey: RowKey): void { + function doCheck (rowKey: RowKey | RowKey[]): void { doUpdateCheckedRowKeys( treeMateRef.value.check(rowKey, mergedCheckedRowKeysRef.value, { cascade: props.cascade }).checkedKeys ) } - function doUncheck (rowKey: RowKey): void { + function doUncheck (rowKey: RowKey | RowKey[]): void { doUpdateCheckedRowKeys( treeMateRef.value.uncheck(rowKey, mergedCheckedRowKeysRef.value, { cascade: props.cascade