fix(data-table): not showing scrollbar when table-layout is auto, closes #518

This commit is contained in:
07akioni 2021-07-25 18:23:51 +08:00
parent 8314e674e7
commit 78c3845f5e
8 changed files with 196 additions and 34 deletions

View File

@ -20,6 +20,7 @@
- Fix `n-layout-sider`'s `width` prop can't be string, closes [#607](https://github.com/TuSimple/naive-ui/issues/607).
- Fix `n-slider` prop `disabled` doesn't work, closes [#641](https://github.com/TuSimple/naive-ui/issues/641).
- Fix `n-input` show clear button when readonly.
- Fix `n-data-table` doesn't show scrollbar when table-layout is auto, closes [#518](https://github.com/TuSimple/naive-ui/issues/518).
## 2.15.6 (2021-07-23)

View File

@ -20,6 +20,7 @@
- 修复 `n-layout-sider` `width` 不能为字符串,关闭 [#607](https://github.com/TuSimple/naive-ui/issues/607)
- 修复 `n-slider` `disabled` 属性不生效,关闭 [#641](https://github.com/TuSimple/naive-ui/issues/641)
- 修复 `n-input` 在只读时仍展示清除按钮
- 修复 `n-data-table` 在 table-layout 为 auto 时不展示滚动条,关闭 [#518](https://github.com/TuSimple/naive-ui/issues/518)
## 2.15.6 (2021-07-23)

View File

@ -36,6 +36,7 @@ ajax-usage
virtual
custom-filter-menu
tree
scroll-debug
```
## Props

View File

@ -0,0 +1,134 @@
# Scroll Debug
```html
Auto Layout Overflow, No Max Height
<n-data-table :columns="columns" :data="data" />
Auto Layout Overflow, Max Height
<n-data-table :columns="columns" :data="data" :max-height="60" />
Fixed Layout Overflow, No Max Height
<n-data-table :columns="columns" :data="data" table-layout="fixed" />
Fixed Layout Overflow, Max Height
<n-data-table
:columns="columns"
:data="data"
table-layout="fixed"
:max-height="60"
/>
Auto Layout No Overflow, No Max Height
<n-data-table :columns="columns" :data="data1" />
Auto Layout No Overflow, Max Height
<n-data-table :columns="columns" :data="data1" :max-height="60" />
Fixed Layout No Overflow, No Max Height
<n-data-table :columns="columns" :data="data1" table-layout="fixed" />
Fixed Layout No Overflow, Max Height
<n-data-table
:columns="columns"
:data="data1"
table-layout="fixed"
:max-height="60"
/>
Auto Layout No Overflow, No Max Height, Small Scroll X
<n-data-table :columns="columns" :data="data1" :scroll-x="300" />
Auto Layout No Overflow, Max Height
<n-data-table
:columns="columns"
:data="data1"
:max-height="60"
:scroll-x="300"
/>
Fixed Layout No Overflow, No Max Height
<n-data-table
:columns="columns"
:data="data1"
table-layout="fixed"
:scroll-x="300"
/>
Fixed Layout No Overflow, Max Height
<n-data-table
:columns="columns"
:data="data1"
table-layout="fixed"
:max-height="60"
:scroll-x="300"
/>
```
```js
import { defineComponent, h } from 'vue'
const label0 =
'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'
const label =
'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
export default defineComponent({
setup () {
return {
columns: [
{
key: '1',
title: '1',
render (rowData) {
return h('div', { style: 'white-space: nowrap;' }, rowData['1'])
}
},
{
key: '2',
title: '2',
render (rowData) {
return h('div', { style: 'white-space: nowrap;' }, rowData['2'])
}
}
],
data: [
{
1: label0,
2: label
},
{
1: label0,
2: label
},
{
1: label0,
2: label
},
{
1: label0,
2: label
}
],
data1: [
{
1: 'x',
2: 'x'
},
{
1: 'x',
2: 'x'
},
{
1: 'x',
2: 'x'
},
{
1: 'x',
2: 'x'
}
]
}
}
})
```

View File

@ -10,6 +10,7 @@ import {
renderSlot,
CSSProperties
} from 'vue'
import { createId } from 'seemly'
import { useConfig, useLocale, useTheme } from '../../_mixins'
import type { ThemeProps } from '../../_mixins'
import { NEmpty } from '../../empty'
@ -42,7 +43,6 @@ import { dataTableInjectionKey } from './interface'
import style from './styles/index.cssr'
import { useGroupHeader } from './use-group-header'
import { useExpand } from './use-expand'
import { createId } from 'seemly'
export const dataTableProps = {
...(useTheme.props as ThemeProps<DataTableTheme>),
@ -242,7 +242,8 @@ export default defineComponent({
const bodyWidthRef = ref<number | null>(null)
const scrollPartRef = ref<'head' | 'body'>('body')
const mainTableInstRef = ref<MainTableRef | null>(null)
const { rowsRef, colsRef, dataRelatedColsRef } = useGroupHeader(props)
const { rowsRef, colsRef, dataRelatedColsRef, hasEllpisisRef } =
useGroupHeader(props)
const {
treeMateRef,
mergedCurrentPageRef,
@ -300,6 +301,17 @@ export default defineComponent({
mergedCurrentPageRef
})
const { localeRef } = useLocale('DataTable')
const mergedTableLayoutRef = computed(() => {
// Layout
// virtual |descrete header | ellpisis => fixed
// = virtual | maxHeight | ellpisis => fixed
if (
props.virtualScroll ||
props.maxHeight !== undefined ||
hasEllpisisRef.value
) { return 'fixed' }
return props.tableLayout
})
provide(dataTableInjectionKey, {
indentRef: toRef(props, 'indent'),
firstContentfulColIndexRef,
@ -354,7 +366,7 @@ export default defineComponent({
'--action-divider-color': actionDividerColor
} as CSSProperties
}),
tableLayoutRef: toRef(props, 'tableLayout'),
mergedTableLayoutRef,
maxHeightRef: toRef(props, 'maxHeight'),
minHeightRef: toRef(props, 'minHeight'),
syncScrollState,

View File

@ -7,7 +7,8 @@ import {
VNode,
watchEffect,
onUnmounted,
PropType
PropType,
CSSProperties
} from 'vue'
import { pxfy, repeat } from 'seemly'
import { VirtualList, VirtualListInst } from 'vueuc'
@ -120,11 +121,12 @@ export default defineComponent({
virtualScrollRef,
componentId,
scrollPartRef,
tableLayoutRef,
mergedTableLayoutRef,
hasChildrenRef,
firstContentfulColIndexRef,
indentRef,
rowPropsRef,
maxHeightRef,
setHeaderScrollLeft,
doUpdateExpandedRowKeys,
handleTableBodyScroll,
@ -258,11 +260,12 @@ export default defineComponent({
hoverKey: hoverKeyRef,
mergedSortState: mergedSortStateRef,
virtualScroll: virtualScrollRef,
tableLayout: tableLayoutRef,
mergedTableLayout: mergedTableLayoutRef,
hasChildren: hasChildrenRef,
firstContentfulColIndex: firstContentfulColIndexRef,
indent: indentRef,
rowProps: rowPropsRef,
maxHeight: maxHeightRef,
setHeaderScrollLeft,
handleMouseenterTable,
handleVirtualListScroll,
@ -282,16 +285,28 @@ export default defineComponent({
scrollX,
mergedClsPrefix,
virtualScroll,
maxHeight,
mergedTableLayout,
onResize,
setHeaderScrollLeft
} = this
const contentStyle = {
width: '100%',
minWidth: formatLength(scrollX)
const scrollable = scrollX !== undefined || maxHeight !== undefined
// For a basic table with auto layout whose content may overflow we will
// make it scrollable, which differs from browser's native behavior.
// For native behavior, see
// https://developer.mozilla.org/en-US/docs/Web/CSS/table-layout
const isBasicAutoLayout = !scrollable && mergedTableLayout === 'auto'
const xScrollable = scrollX !== undefined || isBasicAutoLayout
const contentStyle: CSSProperties = {
minWidth: formatLength(scrollX) || '100%'
}
if (scrollX) contentStyle.width = '100%'
return (
<NScrollbar
ref="scrollbarInstRef"
scrollable={scrollable || isBasicAutoLayout}
class={`${mergedClsPrefix}-data-table-base-table-body`}
theme={mergedTheme.peers.Scrollbar}
themeOverrides={mergedTheme.peerOverrides.Scrollbar}
@ -300,7 +315,7 @@ export default defineComponent({
content={virtualScroll ? this.virtualListContent : undefined}
horizontalRailStyle={{ zIndex: 3 }}
verticalRailStyle={{ zIndex: 3 }}
xScrollable
xScrollable={xScrollable}
onScroll={virtualScroll ? undefined : this.handleTableBodyScroll}
internalOnUpdateScrollLeft={setHeaderScrollLeft}
onResize={onResize}
@ -379,8 +394,6 @@ export default defineComponent({
const { length: rowCount } = mergedData
let hasEllipsis = false
const indentStyle = hasChildren
? { width: pxfy(this.indent) }
: undefined
@ -441,7 +454,6 @@ export default defineComponent({
}
const hoverKey = isCrossRowTd ? this.hoverKey : null
const { ellipsis } = column
if (!hasEllipsis && ellipsis) hasEllipsis = true
return (
<td
key={colKey}
@ -624,8 +636,7 @@ export default defineComponent({
onMouseleave={handleMouseleaveTable}
onMouseenter={handleMouseenterTable}
style={{
tableLayout:
this.showHeader && !hasEllipsis ? this.tableLayout : 'fixed'
tableLayout: this.mergedTableLayout
}}
>
<colgroup>

View File

@ -190,7 +190,7 @@ export interface DataTableInjection {
virtualScrollRef: Ref<boolean>
bodyWidthRef: Ref<number | null>
scrollPartRef: Ref<'head' | 'body'>
tableLayoutRef: Ref<'auto' | 'fixed'>
mergedTableLayoutRef: Ref<'auto' | 'fixed'>
maxHeightRef: Ref<string | number | undefined>
minHeightRef: Ref<string | number | undefined>
rowPropsRef: Ref<CreateRowProps | undefined>

View File

@ -22,15 +22,14 @@ export interface ColItem {
}
type RowItemMap = WeakMap<TableColumn, RowItem>
function getRowsAndCols (
columns: TableColumns
): {
rows: RowItem[][]
cols: ColItem[]
dataRelatedCols: Array<
TableSelectionColumn | TableBaseColumn | TableExpandColumn
>
} {
function getRowsAndCols (columns: TableColumns): {
hasEllpisis: boolean
rows: RowItem[][]
cols: ColItem[]
dataRelatedCols: Array<
TableSelectionColumn | TableBaseColumn | TableExpandColumn
>
} {
const rows: RowItem[][] = []
const cols: ColItem[] = []
const dataRelatedCols: Array<
@ -39,6 +38,7 @@ function getRowsAndCols (
const rowItemMap: RowItemMap = new WeakMap()
let maxDepth = -1
let totalRowSpan = 0
let hasEllpisis = false
function ensureMaxDepth (columns: TableColumns, currentDepth: number): void {
if (currentDepth > maxDepth) {
rows[currentDepth] = []
@ -54,6 +54,7 @@ function getRowsAndCols (
column
})
totalRowSpan += 1
hasEllpisis = !!column.ellipsis
dataRelatedCols.push(column)
}
}
@ -110,25 +111,26 @@ function getRowsAndCols (
ensureColLayout(columns, 0, true)
return {
hasEllpisis,
rows,
cols,
dataRelatedCols
}
}
export function useGroupHeader (
props: DataTableSetupProps
): {
rowsRef: ComputedRef<RowItem[][]>
colsRef: ComputedRef<ColItem[]>
dataRelatedColsRef: ComputedRef<
Array<TableSelectionColumn | TableBaseColumn | TableExpandColumn>
>
} {
export function useGroupHeader (props: DataTableSetupProps): {
rowsRef: ComputedRef<RowItem[][]>
colsRef: ComputedRef<ColItem[]>
hasEllpisisRef: ComputedRef<boolean>
dataRelatedColsRef: ComputedRef<
Array<TableSelectionColumn | TableBaseColumn | TableExpandColumn>
>
} {
const rowsAndCols = computed(() => getRowsAndCols(props.columns))
return {
rowsRef: computed(() => rowsAndCols.value.rows),
colsRef: computed(() => rowsAndCols.value.cols),
hasEllpisisRef: computed(() => rowsAndCols.value.hasEllpisis),
dataRelatedColsRef: computed(() => rowsAndCols.value.dataRelatedCols)
}
}