mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-03-07 13:48:31 +08:00
fix(data-table): fixed column with multiple level header
This commit is contained in:
parent
31caf74e88
commit
37d7fc981b
128
src/data-table/demos/zhCN/fixed-column-debug.demo.md
Normal file
128
src/data-table/demos/zhCN/fixed-column-debug.demo.md
Normal file
@ -0,0 +1,128 @@
|
||||
# Fixed Column Debug
|
||||
|
||||
```html
|
||||
<n-data-table
|
||||
bordered
|
||||
:scroll-x="2000"
|
||||
:max-height="200"
|
||||
:data="data"
|
||||
:columns="columns"
|
||||
:single-line="false"
|
||||
:pagination="pagination"
|
||||
/>
|
||||
```
|
||||
|
||||
```js
|
||||
import { defineComponent, ref } from 'vue'
|
||||
|
||||
function createCols () {
|
||||
return [
|
||||
{
|
||||
title: 'Name',
|
||||
key: 'name',
|
||||
fixed: 'left',
|
||||
children: [
|
||||
{
|
||||
title: '1',
|
||||
key: '1',
|
||||
fixed: 'left',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '2',
|
||||
key: '2',
|
||||
fixed: 'left',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '3',
|
||||
key: '3',
|
||||
fixed: 'left',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '4',
|
||||
key: '4',
|
||||
fixed: 'left',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '5',
|
||||
key: '5',
|
||||
fixed: 'left',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '6',
|
||||
key: '6',
|
||||
fixed: 'left',
|
||||
width: 100
|
||||
}
|
||||
]
|
||||
},
|
||||
{ title: 'Name2', key: 'name1', fixed: 'left', width: 100 },
|
||||
{ title: 'Name3', key: 'name2', fixed: 'left', width: 100 },
|
||||
{
|
||||
title: 'Attrs',
|
||||
key: 'attrs',
|
||||
children: [
|
||||
{
|
||||
title: 'Attack',
|
||||
key: 'attack',
|
||||
children: [
|
||||
{
|
||||
title: 'Physics Attack',
|
||||
key: 'physicsAttack'
|
||||
},
|
||||
{
|
||||
title: 'Magic Attack',
|
||||
key: 'magicAttack'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Defend',
|
||||
key: 'defend'
|
||||
},
|
||||
{
|
||||
title: 'Speed',
|
||||
key: 'speed'
|
||||
},
|
||||
{
|
||||
title: 'Defend1',
|
||||
key: 'defend1'
|
||||
},
|
||||
{
|
||||
title: 'Speed2',
|
||||
key: 'speed2'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
function createData () {
|
||||
return Array.apply(null, { length: 50 }).map((_, i) => {
|
||||
return {
|
||||
key: i,
|
||||
name: `name_${i}`,
|
||||
physicsAttack: `physicsAttack_${i}`,
|
||||
magicAttack: `magicAttack_${i}`,
|
||||
defend: `defend_${i}`,
|
||||
speed: `speed_${i}`
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
data: ref(createData()),
|
||||
columns: ref(createCols()),
|
||||
pagination: ref({
|
||||
pageSize: 10
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
@ -40,6 +40,7 @@ virtual
|
||||
custom-filter-menu
|
||||
tree
|
||||
flex-height
|
||||
fixed-column-debug
|
||||
scroll-debug
|
||||
```
|
||||
|
||||
|
@ -487,8 +487,8 @@ export default defineComponent({
|
||||
key={colKey}
|
||||
style={{
|
||||
textAlign: column.align || undefined,
|
||||
left: pxfy(fixedColumnLeftMap[colKey]),
|
||||
right: pxfy(fixedColumnRightMap[colKey])
|
||||
left: pxfy(fixedColumnLeftMap[colKey]?.start),
|
||||
right: pxfy(fixedColumnRightMap[colKey]?.start)
|
||||
}}
|
||||
colspan={mergedColSpan}
|
||||
rowspan={mergedRowSpan}
|
||||
|
@ -138,21 +138,25 @@ export default defineComponent({
|
||||
const key = getColKey(column)
|
||||
const { ellipsis } = column
|
||||
if (!hasEllipsis && ellipsis) hasEllipsis = true
|
||||
const leftFixed = key in fixedColumnLeftMap
|
||||
const rightFixed = key in fixedColumnRightMap
|
||||
return (
|
||||
<th
|
||||
key={key}
|
||||
style={{
|
||||
textAlign: column.align,
|
||||
left: pxfy(fixedColumnLeftMap[key]),
|
||||
right: pxfy(fixedColumnRightMap[key])
|
||||
left: pxfy(fixedColumnLeftMap[key]?.start),
|
||||
right: pxfy(fixedColumnRightMap[key]?.start)
|
||||
}}
|
||||
colspan={colSpan}
|
||||
rowspan={rowSpan}
|
||||
data-col-key={key}
|
||||
class={[
|
||||
`${mergedClsPrefix}-data-table-th`,
|
||||
column.fixed &&
|
||||
`${mergedClsPrefix}-data-table-th--fixed-${column.fixed}`,
|
||||
(leftFixed || rightFixed) &&
|
||||
`${mergedClsPrefix}-data-table-th--fixed-${
|
||||
leftFixed ? 'left' : 'right'
|
||||
}`,
|
||||
{
|
||||
[`${mergedClsPrefix}-data-table-th--hover`]:
|
||||
isColumnSorting(column, mergedSortState),
|
||||
|
@ -175,8 +175,12 @@ export interface DataTableInjection {
|
||||
rightFixedColumnsRef: Ref<TableColumns>
|
||||
leftActiveFixedColKeyRef: Ref<ColumnKey | null>
|
||||
rightActiveFixedColKeyRef: Ref<ColumnKey | null>
|
||||
fixedColumnLeftMapRef: Ref<Record<ColumnKey, number | undefined>>
|
||||
fixedColumnRightMapRef: Ref<Record<ColumnKey, number | undefined>>
|
||||
fixedColumnLeftMapRef: Ref<
|
||||
Record<ColumnKey, { start: number, end: number } | undefined>
|
||||
>
|
||||
fixedColumnRightMapRef: Ref<
|
||||
Record<ColumnKey, { start: number, end: number } | undefined>
|
||||
>
|
||||
mergedCurrentPageRef: Ref<number>
|
||||
someRowsCheckedRef: Ref<boolean>
|
||||
allRowsCheckedRef: Ref<boolean>
|
||||
|
@ -2,7 +2,7 @@ import { beforeNextFrameOnce } from 'seemly'
|
||||
import { computed, ComputedRef, watch, Ref, ref } from 'vue'
|
||||
import { formatLength } from '../../_utils'
|
||||
import { DataTableSetupProps } from './DataTable'
|
||||
import type { ColumnKey, MainTableRef, TableColumns } from './interface'
|
||||
import type { ColumnKey, MainTableRef, TableColumn } from './interface'
|
||||
import { getColWidth, getColKey } from './utils'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
@ -27,43 +27,53 @@ export function useScroll (
|
||||
return formatLength(props.scrollX)
|
||||
})
|
||||
const leftFixedColumnsRef = computed(() => {
|
||||
const tableColumns: TableColumns = []
|
||||
getFixedColumn(tableColumns, props.columns, 'left')
|
||||
return tableColumns
|
||||
return props.columns.filter((column) => column.fixed === 'left')
|
||||
})
|
||||
const rightFixedColumnsRef = computed(() => {
|
||||
const tableColumns: TableColumns = []
|
||||
getFixedColumn(tableColumns, props.columns, 'right')
|
||||
return tableColumns
|
||||
return props.columns.filter((column) => column.fixed === 'right')
|
||||
})
|
||||
const getFixedColumn = (
|
||||
tableColumns: TableColumns,
|
||||
columns: TableColumns,
|
||||
direction: 'left' | 'right'
|
||||
): void => {
|
||||
columns.forEach((column) => {
|
||||
column.fixed === direction && tableColumns.push(column)
|
||||
if ('children' in column) {
|
||||
getFixedColumn(tableColumns, column.children, direction)
|
||||
}
|
||||
})
|
||||
}
|
||||
const fixedColumnLeftMapRef = computed(() => {
|
||||
const columns: Record<ColumnKey, number | undefined> = {}
|
||||
const columns: Record<
|
||||
ColumnKey,
|
||||
{ start: number, end: number } | undefined
|
||||
> = {}
|
||||
let left = 0
|
||||
for (const column of leftFixedColumnsRef.value) {
|
||||
columns[getColKey(column)] = left
|
||||
left += getColWidth(column) || 0
|
||||
function traverse (cols: TableColumn[]): void {
|
||||
cols.forEach((col) => {
|
||||
const positionInfo = { start: left, end: 0 }
|
||||
columns[getColKey(col)] = positionInfo
|
||||
if ('children' in col) {
|
||||
traverse(col.children)
|
||||
positionInfo.end = left
|
||||
} else {
|
||||
left += getColWidth(col) || 0
|
||||
positionInfo.end = left
|
||||
}
|
||||
})
|
||||
}
|
||||
traverse(leftFixedColumnsRef.value)
|
||||
return columns
|
||||
})
|
||||
const fixedColumnRightMapRef = computed(() => {
|
||||
const columns: Record<ColumnKey, number | undefined> = {}
|
||||
const columns: Record<
|
||||
ColumnKey,
|
||||
{ start: number, end: number } | undefined
|
||||
> = {}
|
||||
let right = 0
|
||||
for (const column of rightFixedColumnsRef.value.reverse()) {
|
||||
columns[getColKey(column)] = right
|
||||
right += column.width || 0
|
||||
function traverse (cols: TableColumn[]): void {
|
||||
cols.forEach((col) => {
|
||||
const positionInfo = { start: right, end: 0 }
|
||||
columns[getColKey(col)] = positionInfo
|
||||
if ('children' in col) {
|
||||
traverse(col.children)
|
||||
positionInfo.end = right
|
||||
} else {
|
||||
right += getColWidth(col) || 0
|
||||
positionInfo.end = right
|
||||
}
|
||||
})
|
||||
}
|
||||
traverse(rightFixedColumnsRef.value.reverse())
|
||||
return columns
|
||||
})
|
||||
function deriveActiveLeftFixedColumn (): void {
|
||||
@ -74,9 +84,9 @@ export function useScroll (
|
||||
let leftActiveFixedColKey = null
|
||||
for (let i = 0; i < leftFixedColumns.length; ++i) {
|
||||
const key = getColKey(leftFixedColumns[i])
|
||||
if (scrollLeft > (fixedColumnLeftMap[key] || 0) - leftWidth) {
|
||||
if (scrollLeft > (fixedColumnLeftMap[key]?.start || 0) - leftWidth) {
|
||||
leftActiveFixedColKey = key
|
||||
leftWidth += getColWidth(leftFixedColumns[i]) || 0
|
||||
leftWidth = fixedColumnLeftMap[key]?.end || 0
|
||||
} else {
|
||||
break
|
||||
}
|
||||
@ -96,11 +106,14 @@ export function useScroll (
|
||||
const key = getColKey(rightFixedColumns[i])
|
||||
if (
|
||||
Math.round(
|
||||
scrollLeft + (fixedColumnRightMap[key] || 0) + tableWidth - rightWidth
|
||||
scrollLeft +
|
||||
(fixedColumnRightMap[key]?.start || 0) +
|
||||
tableWidth -
|
||||
rightWidth
|
||||
) < scrollWidth
|
||||
) {
|
||||
rightActiveFixedColKey = key
|
||||
rightWidth += getColWidth(rightFixedColumns[i]) || 0
|
||||
rightWidth = fixedColumnRightMap[key]?.end || 0
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
@ -21,10 +21,7 @@ const tableProps = {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
singleColumn: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
singleColumn: Boolean,
|
||||
size: {
|
||||
type: String as PropType<'small' | 'medium' | 'large'>,
|
||||
default: 'medium'
|
||||
|
Loading…
Reference in New Issue
Block a user