refactor(data-table): hoist fixed related status to base table from header

This commit is contained in:
07akioni 2020-10-09 22:57:02 +08:00
parent 632a635bdd
commit db6a7d79e7
3 changed files with 101 additions and 138 deletions

View File

@ -1,13 +1,15 @@
<template>
<div class="n-data-table-base-table">
<table-header
ref="headerRef"
:placement="placement"
:columns="columns"
:data="data"
:scroll-x="scrollX"
@update:active-fixed-column="setActiveFixedColumn"
/>
<v-resize-observer @resize="handleHeaderResize">
<table-header
ref="headerRef"
:placement="placement"
:columns="columns"
:data="data"
:scroll-x="scrollX"
@scroll="handleHeaderScroll"
/>
</v-resize-observer>
<table-body
ref="bodyRef"
:style="bodyStyle"
@ -24,17 +26,23 @@
</template>
<script>
import { VResizeObserver } from 'vueuc'
import { ref } from 'vue'
import TableHeader from './TableParts/Header.vue'
import TableBody from './TableParts/Body.vue'
import resizeObserverDelegate from '../../_utils/delegate/resizeObserverDelegate'
import formatLength from '../../_utils/css/formatLength'
export default {
components: {
VResizeObserver,
TableHeader,
TableBody
},
provide () {
return {
NBaseTable: this
}
},
inject: {
NDataTable: {
default: null
@ -94,8 +102,11 @@ export default {
},
data () {
return {
tableWidth: null,
bodyMaxHeight: null,
bodyMinHeight: null
bodyMinHeight: null,
leftActiveFixedColumn: {},
rightActiveFixedColumn: {}
}
},
computed: {
@ -104,37 +115,51 @@ export default {
maxHeight: formatLength(this.bodyMaxHeight),
minHeight: formatLength(this.bodyMinHeight)
}
},
fixedColumnsLeft () {
const columnsLeft = {}
let left = 0
let columns = this.columns
columns.map((column) => {
if (this.NDataTable.leftFixedColumns.indexOf(column) > -1) {
columnsLeft[column.key] = left
}
left = left + this.headerRef.$refs[column.key].offsetWidth
})
return columnsLeft
},
fixedColumnsRight () {
const columnsRight = {}
let right = 0
let columns = this.columns
for (let i = columns.length - 1; i >= 0; i--) {
if (this.NDataTable.rightFixedColumns.indexOf(this.columns[i]) > -1) {
columnsRight[columns[i].key] = right
}
right = right + this.headerRef.$refs[columns[i].key].offsetWidth
}
return columnsRight
}
},
mounted () {
resizeObserverDelegate.registerHandler(
this.getHeaderElement(),
this.setBodyMinMaxHeight
)
this.setBodyMinMaxHeight()
},
beforeUnmount () {
// BUG: beforeUnmount is called twice
// wait for vue 3.0.1 to fix it
resizeObserverDelegate.unregisterHandler(
this.getHeaderElement()
)
},
methods: {
handleHeaderResize (entry) {
this.setBodyMinMaxHeight(entry.contentRect.height)
this.setActiveLeftFixedColumn(entry.target)
this.setActiveRightFixedColumn(entry.target)
},
handleHeaderScroll (e) {
this.setActiveRightFixedColumn(e.target)
this.setActiveLeftFixedColumn(e.target)
this.NDataTable.handleTableHeaderScroll(e)
},
getHeaderElement () {
return this.headerRef.$el
},
getBodyElement () {
return this.bodyRef.getScrollContainer()
},
setActiveFixedColumn (leftActiveFixedColumn, rightActiveFixedColumn) {
const { bodyRef } = this
bodyRef.activeLeft = leftActiveFixedColumn
bodyRef.activeRight = rightActiveFixedColumn
},
setBodyMinMaxHeight () {
setBodyMinMaxHeight (headerHeight) {
const bordered = this.bordered
const headerHeight = this.getHeaderElement().offsetHeight
const maxHeight = this.maxHeight
const minHeight = this.minHeight
if (maxHeight !== null) {
@ -143,6 +168,41 @@ export default {
if (minHeight !== null) {
this.bodyMinHeight = minHeight + (bordered ? -2 : 0) - headerHeight
}
},
setActiveRightFixedColumn (target) {
const rightFixedColumns = this.NDataTable.rightFixedColumns
const scrollLeft = target.scrollLeft
const tableWidth = this.tableWidth
const scrollWidth = target.scrollWidth
let rightWidth = 0
const fixedColumnsRight = this.fixedColumnsRight
const rightActiveFixedColumn = {}
this.rightActiveFixedColumn = rightActiveFixedColumn
for (let i = rightFixedColumns.length - 1; i >= 0; --i) {
const key = rightFixedColumns[i].key
if (scrollLeft + fixedColumnsRight[key] + tableWidth - rightWidth < scrollWidth) {
this.rightActiveFixedColumn = { [key]: true }
rightWidth += rightFixedColumns[i].width
} else {
break
}
}
},
setActiveLeftFixedColumn (target) {
const leftFixedColumns = this.NDataTable.leftFixedColumns
const scrollLeft = target.scrollLeft
let leftWidth = 0
const fixedColumnsLeft = this.fixedColumnsLeft
this.leftActiveFixedColumn = {}
for (let i = 0; i < leftFixedColumns.length; ++i) {
const key = leftFixedColumns[i].key
if (scrollLeft > fixedColumnsLeft[key] - leftWidth) {
this.leftActiveFixedColumn = { [key]: true }
leftWidth += leftFixedColumns[i].width
} else {
break
}
}
}
}
}

View File

@ -44,8 +44,8 @@
[`n-data-table-td--${column.align}-align`]: column.align,
...(column.className && createClassObject(column.className)),
[`n-data-table-td--fixed-${column.fixed}`]: column.width && column.fixed,
'n-data-table-td--shadow-after': activeLeft[column.key],
'n-data-table-td--shadow-before': activeRight[column.key],
'n-data-table-td--shadow-after': NBaseTable.leftActiveFixedColumn[column.key],
'n-data-table-td--shadow-before': NBaseTable.rightActiveFixedColumn[column.key],
'n-data-table-td--selection': column.type === 'selection'
}"
>
@ -84,6 +84,9 @@ export default {
inject: {
NDataTable: {
default: null
},
NBaseTable: {
default: null
}
},
props: {
@ -125,12 +128,6 @@ export default {
scrollbarRef: ref(null)
}
},
data () {
return {
activeLeft: {},
activeRight: {}
}
},
computed: {
formatedScrollX () {
return formatLength(this.scrollX)

View File

@ -5,7 +5,6 @@
}"
:style="headerStyle"
class="n-data-table-base-table-header"
@scroll="handleScroll"
>
<table
ref="body"
@ -37,8 +36,8 @@
'n-data-table-th--filterable': isColumnFilterable(column),
'n-data-table-th--sortable': isColumnSortable(column),
[`n-data-table-th--fixed-${column.fixed}`]: column.fixed && column.width,
'n-data-table-th--shadow-after': leftActiveFixedColumn[column.key],
'n-data-table-th--shadow-before': rightActiveFixedColumn[column.key],
'n-data-table-th--shadow-after': NBaseTable.leftActiveFixedColumn[column.key],
'n-data-table-th--shadow-before': NBaseTable.rightActiveFixedColumn[column.key],
'n-data-table-th--selection': column.type === 'selection'
}"
@click="handleHeaderClick($event, column)"
@ -89,7 +88,6 @@ import SortButton from '../HeaderButton/SortButton.vue'
import FilterButton from '../HeaderButton/FilterButton.vue'
import { createCustomWidthStyle } from '../utils'
import { render } from '../../../_utils/vue'
import resizeObserverDelegate from '../../../_utils/delegate/resizeObserverDelegate'
function isColumnSortable (column) {
return !!column.sorter
@ -133,6 +131,9 @@ export default {
inject: {
NDataTable: {
default: null
},
NBaseTable: {
default: null
}
},
props: {
@ -151,17 +152,6 @@ export default {
data: {
type: Array,
default: () => []
},
// eslint-disable-next-line vue/prop-name-casing
'onUpdate:activeFixedColumn': {
type: Function,
required: true
}
},
data: function () {
return {
leftActiveFixedColumn: [],
rightActiveFixedColumn: []
}
},
computed: {
@ -187,61 +177,12 @@ export default {
return {
overflow: 'scroll'
}
},
fixedColumnsLeft () {
let columnsLeft = {}
let left = 0
let columns = this.columns
columns.map((column) => {
if (this.NDataTable.leftFixedColumns.indexOf(column) > -1) {
columnsLeft[column.key] = left
}
left = left + this.$refs[column.key].offsetWidth
})
return columnsLeft
},
fixedColumnsRight () {
let columnsRight = {}
let right = 0
let columns = this.columns
for (let i = columns.length - 1; i >= 0; i--) {
if (this.NDataTable.rightFixedColumns.indexOf(this.columns[i]) > -1) {
columnsRight[columns[i].key] = right
}
right = right + this.$refs[columns[i].key].offsetWidth
}
return columnsRight
}
},
mounted () {
resizeObserverDelegate.registerHandler(this.$el, this.handleResize)
this.handleResize()
this.setActiveLeftFixedColumn(this.$el)
this.setActiveRightFixedColumn(this.$el)
this.doUpdateActiveFixedColumn(this.leftActiveFixedColumn, this.rightActiveFixedColumn)
},
beforeUnmount () {
resizeObserverDelegate.unregisterHandler(this.$el)
},
methods: {
doUpdateActiveFixedColumn (...args) {
const {
'onUpdate:activeFixedColumn': onUpdateActiveFixedColumn
} = this
onUpdateActiveFixedColumn(...args)
},
isColumnSortable,
isColumnFilterable,
createCustomWidthStyle,
handleResize () {
this.tableWidth = this.$el.offsetWidth
},
handleScroll (e) {
this.setActiveRightFixedColumn(e.target)
this.setActiveLeftFixedColumn(e.target)
this.doUpdateActiveFixedColumn(this.leftActiveFixedColumn, this.rightActiveFixedColumn)
this.NDataTable.handleTableHeaderScroll(e)
},
handleCheckboxInput (column) {
if (this.checkboxIndererminate || this.checkboxChecked) {
this.NDataTable.clearCheckAll(column)
@ -258,41 +199,6 @@ export default {
const activeSorter = this.NDataTable.syntheticActiveSorter
const nextSorter = createNextSorter(column.key, activeSorter, column.sorter)
this.NDataTable.changeSorter(nextSorter)
},
setActiveRightFixedColumn (target) {
const rightFixedColumns = this.NDataTable.rightFixedColumns
const scrollLeft = target.scrollLeft
const tableWidth = this.tableWidth
const scrollWidth = target.scrollWidth
let rightWidth = 0
const fixedColumnsRight = this.fixedColumnsRight
const rightActiveFixedColumn = {}
this.rightActiveFixedColumn = rightActiveFixedColumn
for (let i = rightFixedColumns.length - 1; i >= 0; --i) {
const key = rightFixedColumns[i].key
if (scrollLeft + fixedColumnsRight[key] + tableWidth - rightWidth < scrollWidth) {
this.rightActiveFixedColumn = { [key]: true }
rightWidth += rightFixedColumns[i].width
} else {
break
}
}
},
setActiveLeftFixedColumn (target) {
const leftFixedColumns = this.NDataTable.leftFixedColumns
const scrollLeft = target.scrollLeft
let leftWidth = 0
const fixedColumnsLeft = this.fixedColumnsLeft
this.leftActiveFixedColumn = {}
for (let i = 0; i < leftFixedColumns.length; ++i) {
const key = leftFixedColumns[i].key
if (scrollLeft > fixedColumnsLeft[key] - leftWidth) {
this.leftActiveFixedColumn = { [key]: true }
leftWidth += leftFixedColumns[i].width
} else {
break
}
}
}
}
}