🌐 AI搜索 & 代理 主页
Skip to content

Commit c9715a8

Browse files
authored
perf(tables): make b-th extend b-td instead of using functional wrappers (#4156)
1 parent 3f3a46c commit c9715a8

File tree

3 files changed

+183
-204
lines changed

3 files changed

+183
-204
lines changed

src/components/table/helpers/table-cell.js

Lines changed: 0 additions & 185 deletions
This file was deleted.

src/components/table/td.js

Lines changed: 177 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,185 @@
11
import Vue from '../../utils/vue'
2-
import { omit } from '../../utils/object'
3-
import { props as cellProps, BTableCell } from './helpers/table-cell'
2+
import toString from '../../utils/to-string'
3+
import { isUndefinedOrNull } from '../../utils/inspect'
4+
import normalizeSlotMixin from '../../mixins/normalize-slot'
45

5-
export const props = omit(cellProps, ['header'])
6+
const digitsRx = /^\d+$/
7+
8+
// Parse a rowspan or colspan into a digit (or null if < 1 or NaN)
9+
const parseSpan = val => {
10+
val = parseInt(val, 10)
11+
return digitsRx.test(String(val)) && val > 0 ? val : null
12+
}
13+
14+
/* istanbul ignore next */
15+
const spanValidator = val => isUndefinedOrNull(val) || parseSpan(val) > 0
16+
17+
export const props = {
18+
variant: {
19+
type: String,
20+
default: null
21+
},
22+
colspan: {
23+
type: [Number, String],
24+
default: null,
25+
validator: spanValidator
26+
},
27+
rowspan: {
28+
type: [Number, String],
29+
default: null,
30+
validator: spanValidator
31+
},
32+
stackedHeading: {
33+
type: String,
34+
default: null
35+
},
36+
stickyColumn: {
37+
type: Boolean,
38+
default: false
39+
}
40+
}
641

742
// @vue/component
843
export const BTd = /*#__PURE__*/ Vue.extend({
9-
name: 'BTd',
10-
functional: true,
44+
name: 'BTableCell',
45+
mixins: [normalizeSlotMixin],
46+
inheritAttrs: false,
47+
inject: {
48+
// Injections for feature / attribute detection
49+
bvTable: {
50+
default: null
51+
},
52+
bvTableTbody: {
53+
default: null
54+
},
55+
bvTableThead: {
56+
default: null
57+
},
58+
bvTableTfoot: {
59+
default: null
60+
},
61+
bvTableTr: {
62+
default: null
63+
}
64+
},
1165
props,
12-
render(h, { props, data, children }) {
13-
// `data` already includes any listeners
14-
data.props = { ...props, header: false }
15-
return h(BTableCell, data, children)
66+
computed: {
67+
tag() {
68+
// Overridden by <b-th>
69+
return 'td'
70+
},
71+
isDark() {
72+
return this.bvTable && this.bvTable.dark
73+
},
74+
isStacked() {
75+
return this.bvTable && this.bvTable.isStacked
76+
},
77+
isStackedCell() {
78+
// We only support stacked-heading in tbody in stacked mode
79+
return this.bvTableTbody && this.isStacked
80+
},
81+
isResponsive() {
82+
return this.bvTable && this.bvTable.isResponsive && !this.isStacked
83+
},
84+
isStickyHeader() {
85+
// Needed to handle header background classes, due to lack of
86+
// background color inheritance with Bootstrap v4 table CSS
87+
// Sticky headers only apply to cells in table `thead`
88+
return (
89+
!this.isStacked &&
90+
this.bvTable &&
91+
this.bvTableThead &&
92+
this.bvTableTr &&
93+
this.bvTable.stickyHeader
94+
)
95+
},
96+
isStickyColumn() {
97+
// Needed to handle header background classes, due to lack of
98+
// background color inheritance with Bootstrap v4 table CSS
99+
// Sticky column cells are only available in responsive
100+
// mode (horizontal scrolling) or when sticky header mode
101+
// Applies to cells in `thead`, `tbody` and `tfoot`
102+
return (
103+
(this.isResponsive || this.isStickyHeader) &&
104+
this.stickyColumn &&
105+
!this.isStacked &&
106+
this.bvTable &&
107+
this.bvTableTr
108+
)
109+
},
110+
cellClasses() {
111+
// We use computed props here for improved performance by caching
112+
// the results of the string interpolation
113+
let variant = this.variant
114+
if (
115+
(!variant && this.isStickyHeader && !this.bvTableThead.headVariant) ||
116+
(!variant && this.isStickyColumn)
117+
) {
118+
// Needed for sticky-header mode as Bootstrap v4 table cells do
119+
// not inherit parent's background-color. Boo!
120+
variant = this.bvTableTr.variant || this.bvTable.tableVariant || 'b-table-default'
121+
}
122+
return [
123+
variant ? `${this.isDark ? 'bg' : 'table'}-${variant}` : null,
124+
this.isStickyColumn ? 'b-table-sticky-column' : null
125+
]
126+
},
127+
computedColspan() {
128+
return parseSpan(this.colspan)
129+
},
130+
computedRowspan() {
131+
return parseSpan(this.rowspan)
132+
},
133+
cellAttrs() {
134+
// We use computed props here for improved performance by caching
135+
// the results of the object spread (Object.assign)
136+
const headOrFoot = this.bvTableThead || this.bvTableTfoot
137+
// Make sure col/rowspan's are > 0 or null
138+
const colspan = this.computedColspan
139+
const rowspan = this.computedRowspan
140+
// Default role and scope
141+
let role = 'cell'
142+
let scope = null
143+
144+
// Compute role and scope
145+
// We only add scopes with an explicit span of 1 or greater
146+
if (headOrFoot) {
147+
// Header or footer cells
148+
role = 'columnheader'
149+
scope = colspan > 0 ? 'colspan' : 'col'
150+
} else if (this.tag === 'th') {
151+
// th's in tbody
152+
role = 'rowheader'
153+
scope = rowspan > 0 ? 'rowgroup' : 'row'
154+
}
155+
156+
return {
157+
colspan: colspan,
158+
rowspan: rowspan,
159+
role: role,
160+
scope: scope,
161+
// Allow users to override role/scope plus add other attributes
162+
...this.$attrs,
163+
// Add in the stacked cell label data-attribute if in
164+
// stacked mode (if a stacked heading label is provided)
165+
'data-label':
166+
this.isStackedCell && !isUndefinedOrNull(this.stackedHeading)
167+
? toString(this.stackedHeading)
168+
: null
169+
}
170+
}
171+
},
172+
render(h) {
173+
const content = [this.normalizeSlot('default')]
174+
return h(
175+
this.tag,
176+
{
177+
class: this.cellClasses,
178+
attrs: this.cellAttrs,
179+
// Transfer any native listeners
180+
on: this.$listeners
181+
},
182+
[this.isStackedCell ? h('div', [content]) : content]
183+
)
16184
}
17185
})

0 commit comments

Comments
 (0)