refactor(components): [el-table] use namespace (#5528)

This commit is contained in:
msidolphin 2022-01-22 10:37:59 +08:00 committed by GitHub
parent dd5b84f885
commit 2f521c419c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 214 additions and 148 deletions

View File

@ -10,15 +10,13 @@
</el-table-column>
<el-table-column label="Name" width="180">
<template #default="scope">
<el-popover effect="light" trigger="hover" placement="top">
<el-popover effect="light" trigger="hover" placement="top" width="auto">
<template #default>
<p>name: {{ scope.row.name }}</p>
<p>address: {{ scope.row.address }}</p>
<div>name: {{ scope.row.name }}</div>
<div>address: {{ scope.row.address }}</div>
</template>
<template #reference>
<div class="name-wrapper">
<el-tag>{{ scope.row.name }}</el-tag>
</div>
</template>
</el-popover>
</template>

View File

@ -9,6 +9,11 @@ import type { TableColumnCtx } from './table-column/defaults'
import type { Store } from './store'
import type { TreeNode } from './table/defaults'
const defaultClassNames = {
selection: 'table-column--selection',
expand: 'table__expand-column',
}
export const cellStarts = {
default: {
order: '',
@ -18,7 +23,6 @@ export const cellStarts = {
minWidth: 48,
realWidth: 48,
order: '',
className: 'el-table-column--selection',
},
expand: {
width: 48,
@ -34,6 +38,10 @@ export const cellStarts = {
},
}
export const getDefaultClassName = (type) => {
return defaultClassNames[type] || ''
}
// 这些选项不应该被覆盖
export const cellForced = {
selection: {
@ -105,9 +113,10 @@ export const cellForced = {
return column.label || ''
},
renderCell<T>({ row, store }: { row: T; store: Store<T> }) {
const classes = ['el-table__expand-icon']
const { ns } = store
const classes = [ns.e('expand-icon')]
if (store.states.expandRows.value.indexOf(row) > -1) {
classes.push('el-table__expand-icon--expanded')
classes.push(ns.em('expand-icon', 'expanded'))
}
const callback = function (e: Event) {
e.stopPropagation()
@ -134,7 +143,6 @@ export const cellForced = {
},
sortable: false,
resizable: false,
className: 'el-table__expand-column',
},
}
@ -170,18 +178,19 @@ export function treeCellPrefix<T>({
e.stopPropagation()
store.loadOrToggle(row)
}
const { ns } = store
if (treeNode.indent) {
ele.push(
h('span', {
class: 'el-table__indent',
class: ns.e('indent'),
style: { 'padding-left': `${treeNode.indent}px` },
})
)
}
if (typeof treeNode.expanded === 'boolean' && !treeNode.noLazyChildren) {
const expandClasses = [
'el-table__expand-icon',
treeNode.expanded ? 'el-table__expand-icon--expanded' : '',
ns.e('expand-icon'),
treeNode.expanded ? ns.em('expand-icon', 'expanded') : '',
]
let icon = ArrowRight
if (treeNode.loading) {
@ -200,7 +209,7 @@ export function treeCellPrefix<T>({
return [
h(
ElIcon,
{ class: { 'is-loading': treeNode.loading } },
{ class: { [ns.is('loading')]: treeNode.loading } },
{
default: () => [h(icon)],
}
@ -213,7 +222,7 @@ export function treeCellPrefix<T>({
} else {
ele.push(
h('span', {
class: 'el-table__placeholder',
class: ns.e('placeholder'),
})
)
}

View File

@ -9,16 +9,16 @@
append-to-body
effect="light"
pure
popper-class="el-table-filter"
:popper-class="ns.b()"
persistent
>
<template #content>
<div v-if="multiple">
<div class="el-table-filter__content">
<el-scrollbar wrap-class="el-table-filter__wrap">
<div :class="ns.e('content')">
<el-scrollbar :wrap-class="ns.e('wrap')">
<el-checkbox-group
v-model="filteredValue"
class="el-table-filter__checkbox-group"
:class="ns.e('checkbox-group')"
>
<el-checkbox
v-for="filter in filters"
@ -30,9 +30,9 @@
</el-checkbox-group>
</el-scrollbar>
</div>
<div class="el-table-filter__bottom">
<div :class="ns.e('bottom')">
<button
:class="{ 'is-disabled': filteredValue.length === 0 }"
:class="{ [ns.is('disabled')]: filteredValue.length === 0 }"
:disabled="filteredValue.length === 0"
type="button"
@click="handleConfirm"
@ -44,12 +44,15 @@
</button>
</div>
</div>
<ul v-else class="el-table-filter__list">
<ul v-else :class="ns.e('list')">
<li
:class="{
'is-active': filterValue === undefined || filterValue === null,
}"
class="el-table-filter__list-item"
:class="[
ns.e('list-item'),
{
[ns.is('active')]:
filterValue === undefined || filterValue === null,
},
]"
@click="handleSelect(null)"
>
{{ t('el.table.clearFilter') }}
@ -57,9 +60,8 @@
<li
v-for="filter in filters"
:key="filter.value"
:class="{ 'is-active': isActive(filter) }"
:class="[ns.e('list-item'), ns.is('active', isActive(filter))]"
:label="filter.value"
class="el-table-filter__list-item"
@click="handleSelect(filter.value)"
>
{{ filter.text }}
@ -69,7 +71,10 @@
<template #default>
<span
v-click-outside:[popperPaneRef]="hideFilterPanel"
class="el-table__column-filter-trigger el-none-outline"
:class="[
`${ns.namespace.value}-table__column-filter-trigger`,
`${ns.namespace.value}-none-outline`,
]"
@click="showFilterPanel"
>
<el-icon>
@ -87,7 +92,7 @@ import ElCheckbox from '@element-plus/components/checkbox'
import { ElIcon } from '@element-plus/components/icon'
import { ArrowDown, ArrowUp } from '@element-plus/icons-vue'
import { ClickOutside } from '@element-plus/directives'
import { useLocale } from '@element-plus/hooks'
import { useLocale, useNamespace } from '@element-plus/hooks'
import ElTooltip from '@element-plus/components/tooltip'
import ElScrollbar from '@element-plus/components/scrollbar'
import type { Placement } from '@element-plus/components/popper'
@ -129,7 +134,8 @@ export default defineComponent({
setup(props) {
const instance = getCurrentInstance()
const { t } = useLocale()
const parent = instance.parent as TableHeader
const ns = useNamespace('table-filter')
const parent = instance?.parent as TableHeader
if (!parent.filterPanels.value[props.column.id]) {
parent.filterPanels.value[props.column.id] = instance
}
@ -139,7 +145,7 @@ export default defineComponent({
return props.column && props.column.filters
})
const filterValue = computed({
get: () => (props.column.filteredValue || [])[0],
get: () => (props.column?.filteredValue || [])[0],
set: (value: string) => {
if (filteredValue.value) {
if (typeof value !== 'undefined' && value !== null) {
@ -235,6 +241,7 @@ export default defineComponent({
handleSelect,
isActive,
t,
ns,
showFilterPanel,
hideFilterPanel,
popperPaneRef,

View File

@ -1,4 +1,5 @@
import { nextTick, getCurrentInstance, unref } from 'vue'
import { useNamespace } from '@element-plus/hooks'
import useWatcher from './watcher'
import type { Ref } from 'vue'
@ -37,6 +38,7 @@ function sortColumn<T>(array: TableColumnCtx<T>[]) {
function useStore<T>() {
const instance = getCurrentInstance() as Table<T>
const watcher = useWatcher<T>()
const ns = useNamespace('table')
type StoreStates = typeof watcher.states
const mutations = {
setData(states: StoreStates, data: T[]) {
@ -200,6 +202,7 @@ function useStore<T>() {
nextTick(() => instance.layout.updateScrollY.apply(instance.layout))
}
return {
ns,
...watcher,
mutations,
commit,

View File

@ -14,18 +14,20 @@ function useEvents<T>(props: Partial<TableBodyProps<T>>) {
const table = parent
const cell = getCell(event)
let column: TableColumnCtx<T>
const namespace = table?.vnode.el?.dataset.prefix
if (cell) {
column = getColumnByCell(
{
columns: props.store.states.columns.value,
},
cell
cell,
namespace
)
if (column) {
table.emit(`cell-${name}`, row, column, cell, event)
table?.emit(`cell-${name}`, row, column, cell, event)
}
}
table.emit(`row-${name}`, row, column, event)
table?.emit(`row-${name}`, row, column, event)
}
const handleDoubleClick = (event: Event, row: T) => {
handleEvent(event, row, 'dblclick')
@ -49,16 +51,17 @@ function useEvents<T>(props: Partial<TableBodyProps<T>>) {
) => {
const table = parent
const cell = getCell(event)
const namespace = table?.vnode.el?.dataset.prefix
if (cell) {
const column = getColumnByCell(
{
columns: props.store.states.columns.value,
},
cell
cell,
namespace
)
const hoverState = (table.hoverState = { cell, column, row })
table.emit(
table?.emit(
'cell-mouse-enter',
hoverState.row,
hoverState.column,
@ -71,7 +74,12 @@ function useEvents<T>(props: Partial<TableBodyProps<T>>) {
const cellChild = (event.target as HTMLElement).querySelector(
'.cell'
) as HTMLElement
if (!(hasClass(cellChild, 'el-tooltip') && cellChild.childNodes.length)) {
if (
!(
hasClass(cellChild, `${namespace}-tooltip`) &&
cellChild.childNodes.length
)
) {
return
}
// use range width instead of scrollWidth to determine whether the text is overflowing
@ -102,8 +110,8 @@ function useEvents<T>(props: Partial<TableBodyProps<T>>) {
const cell = getCell(event)
if (!cell) return
const oldHoverState = parent.hoverState
parent.emit(
const oldHoverState = parent?.hoverState
parent?.emit(
'cell-mouse-leave',
oldHoverState?.row,
oldHoverState?.column,

View File

@ -9,6 +9,7 @@ import {
} from 'vue'
import { isClient } from '@vueuse/core'
import { addClass, removeClass } from '@element-plus/utils/dom'
import { useNamespace } from '@element-plus/hooks'
import { hColgroup } from '../h-helper'
import useLayoutObserver from '../layout-observer'
import { removePopper } from '../util'
@ -24,9 +25,10 @@ export default defineComponent({
setup(props) {
const instance = getCurrentInstance()
const parent = inject(TABLE_INJECTION_KEY)
const ns = useNamespace('table')
const { wrappedRowRender, tooltipContent, tooltipTrigger } =
useRender(props)
const { onColumnsChange, onScrollableChange } = useLayoutObserver(parent)
const { onColumnsChange, onScrollableChange } = useLayoutObserver(parent!)
watch(props.store.states.hoverRow, (newVal: any, oldVal: any) => {
if (!props.store.states.isComplex.value || !isClient) return
@ -35,7 +37,7 @@ export default defineComponent({
raf = (fn) => window.setTimeout(fn, 16)
}
raf(() => {
const rows = instance.vnode.el.querySelectorAll('.el-table__row')
const rows = instance?.vnode.el?.querySelectorAll(ns.e('row'))
const oldRow = rows[oldVal]
const newRow = rows[newVal]
if (oldRow) {
@ -55,6 +57,7 @@ export default defineComponent({
})
return {
ns,
onColumnsChange,
onScrollableChange,
wrappedRowRender,
@ -63,13 +66,13 @@ export default defineComponent({
}
},
render() {
const { wrappedRowRender, store } = this
const { ns, wrappedRowRender, store } = this
const data = store.states.data.value || []
const columns = store.states.columns.value
return h(
'table',
{
class: 'el-table__body',
class: ns.e('body'),
cellspacing: '0',
cellpadding: '0',
border: '0',

View File

@ -1,4 +1,5 @@
import { inject } from 'vue'
import { useNamespace } from '@element-plus/hooks'
import {
getFixedColumnOffset,
getFixedColumnsClass,
@ -10,9 +11,10 @@ import type { TableBodyProps } from './defaults'
function useStyles<T>(props: Partial<TableBodyProps<T>>) {
const parent = inject(TABLE_INJECTION_KEY)
const ns = useNamespace('table')
const getRowStyle = (row: T, rowIndex: number) => {
const rowStyle = parent.props.rowStyle
const rowStyle = parent?.props.rowStyle
if (typeof rowStyle === 'function') {
return rowStyle.call(null, {
row,
@ -23,18 +25,18 @@ function useStyles<T>(props: Partial<TableBodyProps<T>>) {
}
const getRowClass = (row: T, rowIndex: number) => {
const classes = ['el-table__row']
const classes = [ns.e('row')]
if (
parent.props.highlightCurrentRow &&
parent?.props.highlightCurrentRow &&
row === props.store.states.currentRow.value
) {
classes.push('current-row')
}
if (props.stripe && rowIndex % 2 === 1) {
classes.push('el-table__row--striped')
classes.push(ns.em('row', 'striped'))
}
const rowClassName = parent.props.rowClassName
const rowClassName = parent?.props.rowClassName
if (typeof rowClassName === 'string') {
classes.push(rowClassName)
} else if (typeof rowClassName === 'function') {
@ -59,7 +61,7 @@ function useStyles<T>(props: Partial<TableBodyProps<T>>) {
row: T,
column: TableColumnCtx<T>
) => {
const cellStyle = parent.props.cellStyle
const cellStyle = parent?.props.cellStyle
let cellStyles = cellStyle ?? {}
if (typeof cellStyle === 'function') {
cellStyles = cellStyle.call(null, {
@ -71,7 +73,7 @@ function useStyles<T>(props: Partial<TableBodyProps<T>>) {
}
const fixedStyle = getFixedColumnOffset(
columnIndex,
props.fixed,
props?.fixed,
props.store
)
ensurePosition(fixedStyle, 'left')
@ -87,9 +89,9 @@ function useStyles<T>(props: Partial<TableBodyProps<T>>) {
) => {
const fixedClasses = column.isSubColumn
? []
: getFixedColumnsClass(columnIndex, props.fixed, props.store)
: getFixedColumnsClass(ns.b(), columnIndex, props?.fixed, props.store)
const classes = [column.id, column.align, column.className, ...fixedClasses]
const cellClassName = parent.props.cellClassName
const cellClassName = parent?.props.cellClassName
if (typeof cellClassName === 'string') {
classes.push(cellClassName)
} else if (typeof cellClassName === 'function') {
@ -102,9 +104,7 @@ function useStyles<T>(props: Partial<TableBodyProps<T>>) {
})
)
}
classes.push('el-table__cell')
classes.push(ns.e('cell'))
return classes.join(' ')
}
const getSpan = (
@ -115,7 +115,7 @@ function useStyles<T>(props: Partial<TableBodyProps<T>>) {
) => {
let rowspan = 1
let colspan = 1
const fn = parent.props.spanMethod
const fn = parent?.props.spanMethod
if (typeof fn === 'function') {
const result = fn({
row,

View File

@ -1,6 +1,12 @@
import { getCurrentInstance, h, ref, computed, watchEffect } from 'vue'
import { getCurrentInstance, h, ref, computed, watchEffect, unref } from 'vue'
import { debugWarn } from '@element-plus/utils/error'
import { cellForced, defaultRenderCell, treeCellPrefix } from '../config'
import { useNamespace } from '@element-plus/hooks'
import {
cellForced,
defaultRenderCell,
treeCellPrefix,
getDefaultClassName,
} from '../config'
import { parseWidth, parseMinWidth } from '../util'
import type { ComputedRef } from 'vue'
@ -16,6 +22,7 @@ function useRender<T>(
const isSubColumn = ref(false)
const realAlign = ref<string>()
const realHeaderAlign = ref<string>()
const ns = useNamespace('table')
watchEffect(() => {
realAlign.value = props.align ? `is-${props.align}` : null
// nextline help render
@ -57,10 +64,17 @@ function useRender<T>(
const source = cellForced[type] || {}
Object.keys(source).forEach((prop) => {
const value = source[prop]
if (value !== undefined) {
column[prop] = prop === 'className' ? `${column[prop]} ${value}` : value
if (prop !== 'className' && value !== undefined) {
column[prop] = value
}
})
const className = getDefaultClassName(type)
if (className) {
const forceClass = `${unref(ns.namespace)}-${className}`
column.className = column.className
? `${column.className} ${forceClass}`
: forceClass
}
return column
}
@ -123,7 +137,7 @@ function useRender<T>(
style: {},
}
if (column.showOverflowTooltip) {
props.class += ' el-tooltip'
props.class = `${props.class} ${unref(ns.namespace)}-tooltip`
props.style = {
width: `${
(data.column.realWidth || Number(data.column.width)) - 1

View File

@ -1,4 +1,5 @@
import { defineComponent, h } from 'vue'
import { useNamespace } from '@element-plus/hooks'
import { hColgroup } from '../h-helper'
import useStyle from './style-helper'
import type { Store } from '../store'
@ -45,15 +46,23 @@ export default defineComponent({
const { getCellClasses, getCellStyles, columns } = useStyle(
props as TableFooter<DefaultRow>
)
const ns = useNamespace('table')
return {
ns,
getCellClasses,
getCellStyles,
columns,
}
},
render() {
const { columns, getCellStyles, getCellClasses, summaryMethod, sumText } =
this
const {
columns,
getCellStyles,
getCellClasses,
summaryMethod,
sumText,
ns,
} = this
const data = this.store.states.data.value
let sums = []
if (summaryMethod) {
@ -95,7 +104,7 @@ export default defineComponent({
return h(
'table',
{
class: 'el-table__footer',
class: ns.e('footer'),
cellspacing: '0',
cellpadding: '0',
border: '0',

View File

@ -1,11 +1,9 @@
import { computed, getCurrentInstance } from 'vue'
import { computed, inject } from 'vue'
import { TABLE_INJECTION_KEY } from '../tokens'
import type { Table } from '../table/defaults'
function useMapState<T>() {
const instance = getCurrentInstance()
const table = instance.parent as Table<T>
const store = table.store
function useMapState() {
const table = inject(TABLE_INJECTION_KEY)
const store = table?.store
const leftFixedLeafCount = computed(() => {
return store.states.fixedLeafColumnsLength.value
})

View File

@ -1,3 +1,4 @@
import { useNamespace } from '@element-plus/hooks'
import {
getFixedColumnOffset,
getFixedColumnsClass,
@ -8,22 +9,23 @@ import type { TableColumnCtx } from '../table-column/defaults'
import type { TableFooter } from '.'
function useStyle<T>(props: TableFooter<T>) {
const { columns } = useMapState<T>()
const { columns } = useMapState()
const ns = useNamespace('table')
const getCellClasses = (columns: TableColumnCtx<T>[], cellIndex: number) => {
const column = columns[cellIndex]
const classes = [
'el-table__cell',
ns.e('cell'),
column.id,
column.align,
column.labelClassName,
...getFixedColumnsClass(cellIndex, column.fixed, props.store),
...getFixedColumnsClass(ns.b(), cellIndex, column.fixed, props.store),
]
if (column.className) {
classes.push(column.className)
}
if (!column.children) {
classes.push('is-leaf')
classes.push(ns.is('leaf'))
}
return classes
}

View File

@ -1,14 +1,13 @@
import { getCurrentInstance, ref } from 'vue'
import { getCurrentInstance, ref, inject } from 'vue'
import { isClient } from '@vueuse/core'
import { hasClass, addClass, removeClass } from '@element-plus/utils/dom'
import { TABLE_INJECTION_KEY } from '../tokens'
import type { TableHeaderProps } from '.'
import type { TableColumnCtx } from '../table-column/defaults'
import type { Table } from '../table/defaults'
function useEvent<T>(props: TableHeaderProps<T>, emit) {
const instance = getCurrentInstance()
const parent = instance.parent as Table<T>
const parent = inject(TABLE_INJECTION_KEY)
const handleFilterClick = (event: Event) => {
event.stopPropagation()
return
@ -20,11 +19,11 @@ function useEvent<T>(props: TableHeaderProps<T>, emit) {
} else if (column.filterable && !column.sortable) {
handleFilterClick(event)
}
parent.emit('header-click', column, event)
parent?.emit('header-click', column, event)
}
const handleHeaderContextMenu = (event: Event, column: TableColumnCtx<T>) => {
parent.emit('header-contextmenu', column, event)
parent?.emit('header-contextmenu', column, event)
}
const draggingColumn = ref(null)
const dragging = ref(false)
@ -38,7 +37,7 @@ function useEvent<T>(props: TableHeaderProps<T>, emit) {
const table = parent
emit('set-drag-visible', true)
const tableEl = table.vnode.el
const tableEl = table?.vnode.el
const tableLeft = tableEl.getBoundingClientRect().left
const columnEl = instance.vnode.el.querySelector(`th.${column.id}`)
const columnRect = columnEl.getBoundingClientRect()
@ -52,7 +51,7 @@ function useEvent<T>(props: TableHeaderProps<T>, emit) {
startColumnLeft: columnRect.left - tableLeft,
tableLeft,
}
const resizeProxy = table.refs.resizeProxy as HTMLElement
const resizeProxy = table?.refs.resizeProxy as HTMLElement
resizeProxy.style.left = `${(dragState.value as any).startLeft}px`
document.onselectstart = function () {
@ -76,7 +75,7 @@ function useEvent<T>(props: TableHeaderProps<T>, emit) {
const finalLeft = parseInt(resizeProxy.style.left, 10)
const columnWidth = finalLeft - startColumnLeft
column.width = column.realWidth = columnWidth
table.emit(
table?.emit(
'header-dragend',
column.width,
startLeft - startColumnLeft,
@ -193,7 +192,7 @@ function useEvent<T>(props: TableHeaderProps<T>, emit) {
states.sortProp.value = sortProp
states.sortOrder.value = sortOrder
parent.store.commit('changeSortCondition')
parent?.store.commit('changeSortCondition')
}
return {

View File

@ -5,17 +5,19 @@ import {
nextTick,
ref,
h,
inject,
} from 'vue'
import ElCheckbox from '@element-plus/components/checkbox'
import { useNamespace } from '@element-plus/hooks'
import FilterPanel from '../filter-panel.vue'
import useLayoutObserver from '../layout-observer'
import { hColgroup } from '../h-helper'
import { TABLE_INJECTION_KEY } from '../tokens'
import useEvent from './event-helper'
import useStyle from './style.helper'
import useUtils from './utils-helper'
import type { ComponentInternalInstance, Ref, PropType } from 'vue'
import type { DefaultRow, Sort, Table } from '../table/defaults'
import type { DefaultRow, Sort } from '../table/defaults'
import type { Store } from '../store'
export interface TableHeader extends ComponentInternalInstance {
state: {
@ -58,15 +60,16 @@ export default defineComponent({
},
setup(props, { emit }) {
const instance = getCurrentInstance() as TableHeader
const parent = instance.parent as Table<unknown>
const storeData = parent.store.states
const parent = inject(TABLE_INJECTION_KEY)
const ns = useNamespace('table')
const storeData = parent?.store.states
const filterPanels = ref({})
const { onColumnsChange, onScrollableChange } = useLayoutObserver(parent)
const { onColumnsChange, onScrollableChange } = useLayoutObserver(parent!)
onMounted(() => {
nextTick(() => {
const { prop, order } = props.defaultSort
const init = true
parent.store.commit('sort', { prop, order, init })
parent?.store.commit('sort', { prop, order, init })
})
})
const {
@ -96,6 +99,7 @@ export default defineComponent({
instance.filterPanels = filterPanels
return {
ns,
columns: storeData.columns,
filterPanels,
onColumnsChange,
@ -118,6 +122,7 @@ export default defineComponent({
},
render() {
const {
ns,
columns,
isGroup,
columnRows,
@ -141,14 +146,14 @@ export default defineComponent({
border: '0',
cellpadding: '0',
cellspacing: '0',
class: 'el-table__header',
class: ns.e('header'),
},
[
hColgroup(columns),
h(
'thead',
{
class: { 'is-group': isGroup },
class: { [ns.is('group')]: isGroup },
},
columnRows.map((subColumns, rowIndex) =>
h(

View File

@ -1,19 +1,20 @@
import { getCurrentInstance } from 'vue'
import { inject } from 'vue'
import { useNamespace } from '@element-plus/hooks'
import {
getFixedColumnsClass,
getFixedColumnOffset,
ensurePosition,
} from '../util'
import { TABLE_INJECTION_KEY } from '../tokens'
import type { TableColumnCtx } from '../table-column/defaults'
import type { Table } from '../table/defaults'
import type { TableHeaderProps } from '.'
function useStyle<T>(props: TableHeaderProps<T>) {
const instance = getCurrentInstance()
const parent = instance.parent as Table<T>
const parent = inject(TABLE_INJECTION_KEY)
const ns = useNamespace('table')
const getHeaderRowStyle = (rowIndex: number) => {
const headerRowStyle = parent.props.headerRowStyle
const headerRowStyle = parent?.props.headerRowStyle
if (typeof headerRowStyle === 'function') {
return headerRowStyle.call(null, { rowIndex })
}
@ -21,8 +22,8 @@ function useStyle<T>(props: TableHeaderProps<T>) {
}
const getHeaderRowClass = (rowIndex: number): string => {
const classes = []
const headerRowClassName = parent.props.headerRowClassName
const classes: string[] = []
const headerRowClassName = parent?.props.headerRowClassName
if (typeof headerRowClassName === 'string') {
classes.push(headerRowClassName)
} else if (typeof headerRowClassName === 'function') {
@ -38,7 +39,7 @@ function useStyle<T>(props: TableHeaderProps<T>) {
row: T,
column: TableColumnCtx<T>
) => {
let headerCellStyles = parent.props.headerCellStyle ?? {}
let headerCellStyles = parent?.props.headerCellStyle ?? {}
if (typeof headerCellStyles === 'function') {
headerCellStyles = headerCellStyles.call(null, {
rowIndex,
@ -67,6 +68,7 @@ function useStyle<T>(props: TableHeaderProps<T>) {
const fixedClasses = column.isSubColumn
? []
: getFixedColumnsClass<T>(
ns.b(),
columnIndex,
column.fixed,
props.store,
@ -89,7 +91,7 @@ function useStyle<T>(props: TableHeaderProps<T>) {
classes.push('is-sortable')
}
const headerCellClassName = parent.props.headerCellClassName
const headerCellClassName = parent?.props.headerCellClassName
if (typeof headerCellClassName === 'string') {
classes.push(headerCellClassName)
} else if (typeof headerCellClassName === 'function') {
@ -103,7 +105,7 @@ function useStyle<T>(props: TableHeaderProps<T>) {
)
}
classes.push('el-table__cell')
classes.push(ns.e('cell'))
return classes.join(' ')
}

View File

@ -1,13 +1,12 @@
import { getCurrentInstance, computed } from 'vue'
import { computed, inject } from 'vue'
import { TABLE_INJECTION_KEY } from '../tokens'
import type { TableColumnCtx } from '../table-column/defaults'
import type { Table } from '../table/defaults'
import type { TableHeaderProps } from '.'
const getAllColumns = <T>(
columns: TableColumnCtx<T>[]
): TableColumnCtx<T>[] => {
const result = []
const result: TableColumnCtx<T>[] = []
columns.forEach((column) => {
if (column.children) {
result.push(column)
@ -53,7 +52,7 @@ const convertToRows = <T>(
rows.push([])
}
const allColumns = getAllColumns(originColumns)
const allColumns: TableColumnCtx<T>[] = getAllColumns(originColumns)
allColumns.forEach((column) => {
if (!column.children) {
@ -69,19 +68,20 @@ const convertToRows = <T>(
}
function useUtils<T>(props: TableHeaderProps<T>) {
const instance = getCurrentInstance()
const parent = instance.parent as Table<T>
const parent = inject(TABLE_INJECTION_KEY)
const columnRows = computed(() => {
return convertToRows(props.store.states.originColumns.value)
})
const isGroup = computed(() => {
const result = columnRows.value.length > 1
if (result) parent.state.isGroup.value = true
if (result && parent) {
parent.state.isGroup.value = true
}
return result
})
const toggleAllSelection = (event: Event) => {
event.stopPropagation()
parent.store.commit('toggleAllSelection')
parent?.store.commit('toggleAllSelection')
}
return {
isGroup,

View File

@ -136,14 +136,16 @@ class TableLayout<T> {
updateElsHeight() {
if (!this.table.$ready) return nextTick(() => this.updateElsHeight())
const { headerWrapper, appendWrapper, footerWrapper, bodyWrapper } =
this.table.refs
const {
headerWrapper,
appendWrapper,
footerWrapper,
tableHeader,
tableBody,
} = this.table.refs
this.appendHeight.value = appendWrapper ? appendWrapper.offsetHeight : 0
if (this.showHeader && !headerWrapper) return
const headerTrElm: HTMLElement = headerWrapper
? headerWrapper.querySelector('.el-table__header tr')
: null
const headerTrElm: HTMLElement = tableHeader ? tableHeader.$el : null
const noneHeader = this.headerDisplayNone(headerTrElm)
const headerHeight = (this.headerHeight.value = !this.showHeader
@ -159,7 +161,7 @@ class TableLayout<T> {
return nextTick(() => this.updateElsHeight())
}
const tableHeight = (this.tableHeight.value =
this.table.vnode.el.clientHeight)
this.table?.vnode.el?.clientHeight)
const footerHeight = (this.footerHeight.value = footerWrapper
? footerWrapper.offsetHeight
: 0)
@ -169,8 +171,7 @@ class TableLayout<T> {
}
this.bodyHeight.value =
tableHeight - headerHeight - footerHeight + (footerWrapper ? 1 : 0)
this.bodyScrollHeight.value =
bodyWrapper.querySelector('.el-table__body')?.scrollHeight!
this.bodyScrollHeight.value = tableBody?.$el.scrollHeight!
}
this.fixedBodyHeight.value = this.scrollX.value
? this.bodyHeight.value - this.gutterWidth

View File

@ -3,28 +3,29 @@
ref="tableWrapper"
:class="[
{
'el-table--fit': fit,
'el-table--striped': stripe,
'el-table--border': border || isGroup,
'el-table--hidden': isHidden,
'el-table--group': isGroup,
'el-table--fluid-height': maxHeight,
'el-table--scrollable-x': layout.scrollX.value,
'el-table--scrollable-y': layout.scrollY.value,
'el-table--enable-row-hover': !store.states.isComplex.value,
'el-table--enable-row-transition':
[ns.m('fit')]: fit,
[ns.m('striped')]: stripe,
[ns.m('border')]: border || isGroup,
[ns.m('hidden')]: isHidden,
[ns.m('group')]: isGroup,
[ns.m('fluid-height')]: maxHeight,
[ns.m('scrollable-x')]: layout.scrollX.value,
[ns.m('scrollable-y')]: layout.scrollY.value,
[ns.m('enable-row-hover')]: !store.states.isComplex.value,
[ns.m('enable-row-transition')]:
(store.states.data.value || []).length !== 0 &&
(store.states.data.value || []).length < 100,
'has-footer': showSummary,
},
tableSize ? `el-table--${tableSize}` : '',
ns.m(tableSize),
className,
'el-table',
ns.b(),
]"
:style="style"
:data-prefix="ns.namespace.value"
@mouseleave="handleMouseLeave()"
>
<div class="el-table__inner-wrapper">
<div :class="ns.e('inner-wrapper')">
<div ref="hiddenColumns" class="hidden-columns">
<slot></slot>
</div>
@ -32,7 +33,7 @@
v-if="showHeader"
ref="headerWrapper"
v-mousewheel="handleHeaderFooterMousewheel"
class="el-table__header-wrapper"
:class="ns.e('header-wrapper')"
>
<table-header
ref="tableHeader"
@ -43,9 +44,10 @@
@set-drag-visible="setDragVisible"
/>
</div>
<div ref="bodyWrapper" :style="bodyHeight" class="el-table__body-wrapper">
<div ref="bodyWrapper" :style="bodyHeight" :class="ns.e('body-wrapper')">
<el-scrollbar ref="scrollWrapper" :height="height">
<table-body
ref="tableBody"
:context="context"
:highlight="highlightCurrentRow"
:row-class-name="rowClassName"
@ -61,29 +63,29 @@
v-if="isEmpty"
ref="emptyBlock"
:style="emptyBlockStyle"
class="el-table__empty-block"
:class="ns.e('empty-block')"
>
<span class="el-table__empty-text">
<span :class="ns.e('empty-text')">
<slot name="empty">{{ computedEmptyText }}</slot>
</span>
</div>
<div
v-if="$slots.append"
ref="appendWrapper"
class="el-table__append-wrapper"
:class="ns.e('append-wrapper')"
>
<slot name="append"></slot>
</div>
</el-scrollbar>
</div>
<div v-if="border || isGroup" class="el-table__border-left-patch"></div>
<div v-if="border || isGroup" :class="ns.e('border-left-patch')"></div>
</div>
<div
v-if="showSummary"
v-show="!isEmpty"
ref="footerWrapper"
v-mousewheel="handleHeaderFooterMousewheel"
class="el-table__footer-wrapper"
:class="ns.e('footer-wrapper')"
>
<table-footer
:border="border"
@ -97,7 +99,7 @@
<div
v-show="resizeProxyVisible"
ref="resizeProxy"
class="el-table__column-resize-proxy"
:class="ns.e('column-resize-proxy')"
></div>
</div>
</template>
@ -106,7 +108,7 @@
import { defineComponent, getCurrentInstance, computed, provide } from 'vue'
import debounce from 'lodash/debounce'
import { Mousewheel } from '@element-plus/directives'
import { useLocale } from '@element-plus/hooks'
import { useLocale, useNamespace } from '@element-plus/hooks'
import ElScrollbar from '@element-plus/components/scrollbar'
import { createStore } from './store/helper'
import TableLayout from './table-layout'
@ -156,6 +158,7 @@ export default defineComponent({
setup(props) {
type Row = typeof props.data[number]
const { t } = useLocale()
const ns = useNamespace('table')
const table = getCurrentInstance() as Table<Row>
provide(TABLE_INJECTION_KEY, table)
const store = createStore<Row>(table, props)
@ -223,6 +226,7 @@ export default defineComponent({
})
return {
ns,
layout,
store,
handleHeaderFooterMousewheel,

View File

@ -136,9 +136,12 @@ export const getColumnByCell = function <T>(
table: {
columns: TableColumnCtx<T>[]
},
cell: HTMLElement
cell: HTMLElement,
namespace: string
): null | TableColumnCtx<T> {
const matches = (cell.className || '').match(/el-table_[^\s]+/gm)
const matches = (cell.className || '').match(
new RegExp(`${namespace}-table_[^\\s]+`, 'gm')
)
if (matches) {
return getColumnById(table, matches[0])
}
@ -426,6 +429,7 @@ export const isFixedColumn = <T>(
}
export const getFixedColumnsClass = <T>(
namespace: string,
index: number,
fixed: string | boolean,
store: any,
@ -435,7 +439,7 @@ export const getFixedColumnsClass = <T>(
const { direction, start } = isFixedColumn(index, fixed, store, realColumns)
if (direction) {
const isLeft = direction === 'left'
classes.push(`el-table-fixed-column--${direction}`)
classes.push(`${namespace}-fixed-column--${direction}`)
if (isLeft && start === store.states.fixedLeafColumnsLength.value - 1) {
classes.push('is-last-column')
} else if (