diff --git a/examples/views/grid/Group.vue b/examples/views/grid/Group.vue
index aa079989ab12279764c02940b28c6605f856391f..cd3909f332ea8b2d43eb34a5adfb20a5d5fef077 100644
--- a/examples/views/grid/Group.vue
+++ b/examples/views/grid/Group.vue
@@ -10,6 +10,17 @@
{{ demoCodes[0] }}
{{ demoCodes[1] }}
+
+
定制表头单元格所占的行
+
+
+ {{ $t('app.body.button.showCode') }}
+
+
+ {{ demoCodes[2] }}
+ {{ demoCodes[3] }}
+
+
@@ -53,9 +64,49 @@ export default defineComponent({
{ id: 10008, name: 'Test8', nickname: 'T8', role: 'Develop', sex: 'Man', age: 35, address: 'Shenzhen' }
]
})
-
+ const gridOptions2 = reactive({
+ border: true,
+ stripe: true,
+ resizable: true,
+ useCustomHeaderRowSpan: true,
+ height: 500,
+ columns: [
+ {
+ title: '序号',
+ customRowSpan: 3,
+ fixed: 'left',
+ children: [{ type: 'seq', title: '1' }]
+ },
+ {
+ title: '基本信息',
+ children: [
+ { title: 'Name', customRowSpan: 2, children: [{ field: 'name', title: '2' }] },
+ {
+ title: '其他信息',
+ children: [
+ { title: 'Nickname', children: [{ field: 'nickname', title: '3' }] },
+ { title: 'Age', children: [{ field: 'age', title: '4' }] }
+ ]
+ },
+ { title: 'Sex', customRowSpan: 2, children: [{ field: 'sex', title: '5' }] }
+ ]
+ },
+ { title: 'Address', customRowSpan: 3, children: [{ field: 'address', title: '6', showOverflow: true }] }
+ ],
+ data: [
+ { id: 10001, name: 'Test1', nickname: 'T1', role: 'Develop', sex: 'Man', age: 28, address: 'Shenzhen' },
+ { id: 10002, name: 'Test2', nickname: 'T2', role: 'Test', sex: 'Women', age: 22, address: 'Guangzhou' },
+ { id: 10003, name: 'Test3', nickname: 'T3', role: 'PM', sex: 'Man', age: 32, address: 'Shanghai' },
+ { id: 10004, name: 'Test4', nickname: 'T4', role: 'Designer', sex: 'Women', age: 23, address: 'Shenzhen' },
+ { id: 10005, name: 'Test5', nickname: 'T5', role: 'Develop', sex: 'Women', age: 30, address: 'Shanghai' },
+ { id: 10006, name: 'Test6', nickname: 'T6', role: 'Designer', sex: 'Women', age: 21, address: 'Shenzhen' },
+ { id: 10007, name: 'Test7', nickname: 'T7', role: 'Test', sex: 'Man', age: 29, address: 'Shenzhen' },
+ { id: 10008, name: 'Test8', nickname: 'T8', role: 'Develop', sex: 'Man', age: 35, address: 'Shenzhen' }
+ ]
+ })
return {
gridOptions,
+ gridOptions2,
demoCodes: [
`
@@ -106,6 +157,62 @@ export default defineComponent({
}
}
})
+ `,
+ `
+
+ `,
+ `
+ import { defineComponent, reactive } from 'vue'
+ import { VxeGridProps } from 'vxe-table'
+
+ export default defineComponent({
+ setup () {
+ const gridOptions = reactive({
+ border: true,
+ stripe: true,
+ resizable: true,
+ useCustomHeaderRowSpan: true,
+ height: 500,
+ columns: [
+ {
+ title: '序号',
+ customRowSpan: 3,
+ fixed: 'left',
+ children: [{ type: 'seq', title: '1' }]
+ },
+ {
+ title: '基本信息',
+ children: [
+ { title: 'Name', customRowSpan: 2, children: [{ field: 'name', title: '2' }] },
+ {
+ title: '其他信息',
+ children: [
+ { title: 'Nickname', children: [{ field: 'nickname', title: '3' }] },
+ { title: 'Age', children: [{ field: 'age', title: '4' }] }
+ ]
+ },
+ { title: 'Sex', customRowSpan: 2, children: [{ field: 'sex', title: '5' }] }
+ ]
+ },
+ { title: 'Address', customRowSpan: 3, children: [{ field: 'address', title: '6', showOverflow: true }] }
+ ],
+ data: [
+ { id: 10001, name: 'Test1', nickname: 'T1', role: 'Develop', sex: 'Man', age: 28, address: 'Shenzhen' },
+ { id: 10002, name: 'Test2', nickname: 'T2', role: 'Test', sex: 'Women', age: 22, address: 'Guangzhou' },
+ { id: 10003, name: 'Test3', nickname: 'T3', role: 'PM', sex: 'Man', age: 32, address: 'Shanghai' },
+ { id: 10004, name: 'Test4', nickname: 'T4', role: 'Designer', sex: 'Women', age: 23, address: 'Shenzhen' },
+ { id: 10005, name: 'Test5', nickname: 'T5', role: 'Develop', sex: 'Women', age: 30, address: 'Shanghai' },
+ { id: 10006, name: 'Test6', nickname: 'T6', role: 'Designer', sex: 'Women', age: 21, address: 'Shenzhen' },
+ { id: 10007, name: 'Test7', nickname: 'T7', role: 'Test', sex: 'Man', age: 29, address: 'Shenzhen' },
+ { id: 10008, name: 'Test8', nickname: 'T8', role: 'Develop', sex: 'Man', age: 35, address: 'Shenzhen' }
+ ]
+ })
+
+ return {
+ gridOptions
+ }
+ }
+ })
`
]
}
diff --git a/examples/views/table/base/Group.vue b/examples/views/table/base/Group.vue
index ffba00b628d523a8dc5ccdb52259311d2d8f2019..d58b972fc41cc54b3e4be2007270d4de2fd1aa61 100644
--- a/examples/views/table/base/Group.vue
+++ b/examples/views/table/base/Group.vue
@@ -1,5 +1,6 @@
+
当数据结构比较复杂的时候,可以使用多级表头来更加直观的显示数据
{{ demoCodes[2] }}
{{ demoCodes[3] }}
+
+
+
+ 定制表头单元格所占的行
+
+
+
+ 切换第一列固定
+ 切换第二列固定
+ 切换第四列固定
+ 切换第五列固定
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('app.body.button.showCode') }}
+
+
+ {{ demoCodes[4] }}
+ {{ demoCodes[5] }}
+
@@ -123,11 +194,39 @@ export default defineComponent({
}
}
+ const xTable3 = ref({} as VxeTableInstance)
+ const tableData3 = ref([
+ { id: 10001, name: 'Test1', role: 'Develop', sex: 'Man', age: 28, address: 'test abc' },
+ { id: 10002, name: 'Test2', role: 'Test', sex: 'Women', age: 22, address: 'Guangzhou' },
+ { id: 10003, name: 'Test3', role: 'PM', sex: 'Man', age: 32, address: 'Shanghai' },
+ { id: 10004, name: 'Test4', role: 'Designer', sex: 'Women', age: 23, address: 'test abc' },
+ { id: 10005, name: 'Test5', role: 'Develop', sex: 'Women', age: 30, address: 'Shanghai' },
+ { id: 10006, name: 'Test6', role: 'Designer', sex: 'Women', age: 21, address: 'test abc' },
+ { id: 10007, name: 'Test7', role: 'Test', sex: 'Man', age: 29, address: 'test abc' },
+ { id: 10008, name: 'Test8', role: 'Develop', sex: 'Man', age: 35, address: 'test abc' }
+ ])
+
+ const toggleFixedColumn3 = (field: string, type: VxeColumnPropTypes.Fixed) => {
+ const $table = xTable3.value
+ const column = $table.getColumnByField(field)
+ if (column) {
+ const groupFixed = column.fixed ? null : type
+ // 将分组整体设置固定列
+ XEUtils.eachTree([column], column => {
+ column.fixed = groupFixed
+ })
+ // 刷新列
+ $table.refreshColumn()
+ }
+ }
return {
tableData1,
xTable2,
tableData2,
toggleFixedColumn,
+ xTable3,
+ tableData3,
+ toggleFixedColumn3,
demoCodes: [
`
+
+ 切换第一列固定
+ 切换第二列固定
+ 切换第四列固定
+ 切换第五列固定
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `,
+ `
+ import { defineComponent, ref } from 'vue'
+ import { VxeTableInstance, VxeColumnPropTypes } from 'vxe-table'
+ import XEUtils from 'xe-utils'
+
+ export default defineComponent({
+ setup () {
+ const xTable3 = ref({} as VxeTableInstance)
+
+ const tableData3 = ref([
+ { id: 10001, name: 'Test1', role: 'Develop', sex: 'Man', age: 28, address: 'test abc' },
+ { id: 10002, name: 'Test2', role: 'Test', sex: 'Women', age: 22, address: 'Guangzhou' },
+ { id: 10003, name: 'Test3', role: 'PM', sex: 'Man', age: 32, address: 'Shanghai' },
+ { id: 10004, name: 'Test4', role: 'Designer', sex: 'Women', age: 23, address: 'test abc' },
+ { id: 10005, name: 'Test5', role: 'Develop', sex: 'Women', age: 30, address: 'Shanghai' },
+ { id: 10006, name: 'Test6', role: 'Designer', sex: 'Women', age: 21, address: 'test abc' },
+ { id: 10007, name: 'Test7', role: 'Test', sex: 'Man', age: 29, address: 'test abc' },
+ { id: 10008, name: 'Test8', role: 'Develop', sex: 'Man', age: 35, address: 'test abc' }
+ ])
+
+ const toggleFixedColumn3 = (field: string, type: VxeColumnPropTypes.Fixed) => {
+ const $table = xTable3.value
+ const column = $table.getColumnByField(field)
+ if (column) {
+ const groupFixed = column.fixed ? null : type
+ // 将分组整体设置固定列
+ XEUtils.eachTree([column], column => {
+ column.fixed = groupFixed
+ })
+ // 刷新列
+ $table.refreshColumn()
+ }
+ }
+
+ return {
+ xTable3,
+ tableData3,
+ toggleFixedColumn3
+ }
+ }
+ }
`
]
}
diff --git a/packages/export/src/hook.ts b/packages/export/src/hook.ts
index 38a25dd78b626ea421ae69126d9182a2b3c9d438..c73aefb5f4639583b81753261c14dacf6d48a2fb 100644
--- a/packages/export/src/hook.ts
+++ b/packages/export/src/hook.ts
@@ -31,7 +31,7 @@ const getConvertColumns = (columns: any) => {
return result
}
-const convertToRows = (originColumns: any): any[][] => {
+const convertToRows = (originColumns: any, useCustomRowSpan? : boolean): any[][] => {
let maxLevel = 1
const traverse = (column: any, parent?: any) => {
if (parent) {
@@ -63,14 +63,46 @@ const convertToRows = (originColumns: any): any[][] => {
}
const allColumns = getConvertColumns(originColumns)
-
+ const getGroupParentRowSpan = (columnId:string) => {
+ let r = 0
+ for (let i = 0; i < allColumns.length; i++) {
+ const column = allColumns[i]
+ if (column.id === columnId) {
+ if (column._rowSpan && column._rowSpan > 1) {
+ r = r + column._rowSpan
+ }
+ if (column.parentId) {
+ r = r + getGroupParentRowSpan(column.parentId)
+ }
+ }
+ }
+ return r
+ }
allColumns.forEach((column: any) => {
- if (column.childNodes && column.childNodes.length) {
- column._rowSpan = 1
+ if (useCustomRowSpan) {
+ if (column.customRowSpan) {
+ column._rowSpan = column.customRowSpan
+ } else {
+ column._rowSpan = 1
+ }
+ let alevel = column._level - 1
+ if (column.parentId) {
+ let parentRowSpan = getGroupParentRowSpan(column.parentId)
+ parentRowSpan = parentRowSpan > 0 ? parentRowSpan - 1 : 0
+ alevel = alevel + parentRowSpan
+ if (alevel >= maxLevel) {
+ alevel = maxLevel - 1
+ }
+ }
+ rows[alevel].push(column)
} else {
- column._rowSpan = maxLevel - column._level + 1
+ if (column.childNodes && column.childNodes.length) {
+ column._rowSpan = 1
+ } else {
+ column._rowSpan = maxLevel - column._level + 1
+ }
+ rows[column._level - 1].push(column)
}
- rows[column._level - 1].push(column)
})
return rows
diff --git a/packages/header/src/header.ts b/packages/header/src/header.ts
index afec0dffc3718aa55f21b8bad7027d03c9c319de..25798340a4adcf9c1c2e1bba68d3bd6d2b3e1678 100644
--- a/packages/header/src/header.ts
+++ b/packages/header/src/header.ts
@@ -15,7 +15,8 @@ export default defineComponent({
tableColumn: Array as PropType,
tableGroupColumn: Array as PropType,
fixedColumn: Array as PropType,
- fixedType: { type: String as PropType, default: null }
+ fixedType: { type: String as PropType, default: null },
+ useCustomHeaderRowSpan: { type: Boolean, default: false }
},
setup (props) {
const $xetable = inject('$xetable', {} as VxeTableConstructor & VxeTableMethods & VxeTablePrivateMethods)
@@ -35,7 +36,7 @@ export default defineComponent({
const uploadColumn = () => {
const { isGroup } = tableReactData
- headerColumn.value = isGroup ? convertToRows(props.tableGroupColumn) : []
+ headerColumn.value = isGroup ? convertToRows(props.tableGroupColumn, props.useCustomHeaderRowSpan) : []
}
const resizeMousedown = (evnt: MouseEvent, params: any) => {
diff --git a/packages/header/src/util.ts b/packages/header/src/util.ts
index 39618b54e7624cb455ba35f5c60d3fff9a659715..c91654ffe0a33fcdd7755f6ccbb18fe0debd38b6 100644
--- a/packages/header/src/util.ts
+++ b/packages/header/src/util.ts
@@ -14,7 +14,7 @@ const getAllColumns = (columns: any, parentColumn?: any) => {
return result
}
-export const convertToRows = (originColumns: any): any[][] => {
+export const convertToRows = (originColumns: any, useCustomRowSpan?: boolean): any[][] => {
let maxLevel = 1
const traverse = (column: any, parent?: any) => {
if (parent) {
@@ -49,13 +49,48 @@ export const convertToRows = (originColumns: any): any[][] => {
const allColumns = getAllColumns(originColumns)
+ // rowSpan 计算
+ const getGroupParentRowSpan = (columnId: string) => {
+ let r = 0
+ for (let i = 0; i < allColumns.length; i++) {
+ const column = allColumns[i]
+ if (column.id === columnId) {
+ if (column.rowSpan && column.rowSpan > 1) {
+ r = r + column.rowSpan
+ }
+ if (column.parentId) {
+ r = r + getGroupParentRowSpan(column.parentId)
+ }
+ }
+ }
+ return r
+ }
+
allColumns.forEach((column) => {
- if (column.children && column.children.length && column.children.some((column: any) => column.visible)) {
- column.rowSpan = 1
+ if (useCustomRowSpan) {
+ if (column.customRowSpan) {
+ column.rowSpan = column.customRowSpan
+ } else {
+ column.rowSpan = 1
+ }
+ let alevel = column.level - 1
+ if (column.parentId) {
+ let parentRowSpan = getGroupParentRowSpan(column.parentId)
+ parentRowSpan = parentRowSpan > 0 ? parentRowSpan - 1 : 0
+ alevel = alevel + parentRowSpan
+ if (alevel >= maxLevel) {
+ alevel = maxLevel - 1
+ }
+ }
+ rows[alevel].push(column)
} else {
- column.rowSpan = maxLevel - column.level + 1
+ if (column.children && column.children.length && column.children.some((column: any) => column.visible)) {
+ column.rowSpan = 1
+ } else {
+ column.rowSpan = maxLevel - column.level + 1
+ }
+ rows[column.level - 1].push(column)
}
- rows[column.level - 1].push(column)
})
return rows
diff --git a/packages/table/src/column.ts b/packages/table/src/column.ts
index 4ab9d3ae72fc1d8df0b8b897bc462f4fba718941..d8476582e304010f0f32f4517397fac1becb88b4 100644
--- a/packages/table/src/column.ts
+++ b/packages/table/src/column.ts
@@ -27,6 +27,8 @@ export const columnProps = {
headerAlign: String as PropType,
// 表尾列的对齐方式
footerAlign: String as PropType,
+ // 定制行高
+ customRowSpan: { type: [Number, String] as PropType, default: 1 },
// 当内容过长时显示为省略号
showOverflow: { type: [Boolean, String] as PropType, default: null },
// 当表头内容过长时显示为省略号
diff --git a/packages/table/src/columnInfo.ts b/packages/table/src/columnInfo.ts
index 8fe97ad0cd6a382399f901604583ad890a5cf8a1..48a698c02b0f73efbaa7d5327d173980a8366188 100644
--- a/packages/table/src/columnInfo.ts
+++ b/packages/table/src/columnInfo.ts
@@ -75,6 +75,7 @@ export class ColumnInfo {
className: _vm.className,
headerClassName: _vm.headerClassName,
footerClassName: _vm.footerClassName,
+ customRowSpan: _vm.customRowSpan,
formatter: formatter,
sortable: _vm.sortable,
sortBy: _vm.sortBy,
diff --git a/packages/table/src/props.ts b/packages/table/src/props.ts
index db9229c5701199528187c20b87fd1b5ad179adb2..94c25b627acf85c37badfe9419dc44014f5d3881 100644
--- a/packages/table/src/props.ts
+++ b/packages/table/src/props.ts
@@ -160,5 +160,7 @@ export default {
// (可能会被废弃的参数,不要使用)
delayHover: { type: Number as PropType, default: () => GlobalConfig.table.delayHover as number },
// 额外的参数
- params: Object as PropType
+ params: Object as PropType,
+ // 使用自定义表头单元格行数方式
+ useCustomHeaderRowSpan: { type: Boolean as PropType, default: () => GlobalConfig.table.useCustomHeaderRowSpan }
}
diff --git a/packages/table/src/table.ts b/packages/table/src/table.ts
index 77699a4d0ef0f242aa9be0b8ed616ddcc40e1889..9d0bfe2b8dff5d562c85f061e53b3a3f032bc202 100644
--- a/packages/table/src/table.ts
+++ b/packages/table/src/table.ts
@@ -63,6 +63,7 @@ export default defineComponent({
parentHeight: 0,
// 是否使用分组表头
isGroup: false,
+ useCustomHeaderRowSpan: false,
isAllOverflow: false,
// 复选框属性,是否全选
isAllSelected: false,
@@ -892,6 +893,7 @@ export default defineComponent({
const mouseOpts = computeMouseOpts.value
const isGroup = collectColumn.some(hasChildrenList)
let isAllOverflow = !!props.showOverflow
+ const useCustomHeaderRowSpan = !!props.useCustomHeaderRowSpan
let expandColumn: any
let treeNodeColumn: any
let checkboxColumn: any
@@ -969,7 +971,7 @@ export default defineComponent({
errLog('vxe.error.errConflicts', ['mouse-config.area', 'column.type=expand'])
}
}
-
+ reactData.useCustomHeaderRowSpan = useCustomHeaderRowSpan
reactData.isGroup = isGroup
reactData.treeNodeColumn = treeNodeColumn
reactData.expandColumn = expandColumn
@@ -5897,7 +5899,7 @@ export default defineComponent({
const renderVN = () => {
const { loading, stripe, showHeader, height, treeConfig, mouseConfig, showFooter, highlightCell, highlightHoverRow, highlightHoverColumn, editConfig } = props
- const { isGroup, overflowX, overflowY, scrollXLoad, scrollYLoad, scrollbarHeight, tableData, tableColumn, tableGroupColumn, footerTableData, initStore, columnStore, filterStore } = reactData
+ const { isGroup, useCustomHeaderRowSpan, overflowX, overflowY, scrollXLoad, scrollYLoad, scrollbarHeight, tableData, tableColumn, tableGroupColumn, footerTableData, initStore, columnStore, filterStore } = reactData
const { leftList, rightList } = columnStore
const tipConfig = computeTipConfig.value
const treeOpts = computeTreeOpts.value
@@ -5956,7 +5958,8 @@ export default defineComponent({
ref: refTableHeader,
tableData,
tableColumn,
- tableGroupColumn
+ tableGroupColumn,
+ useCustomHeaderRowSpan
}) : createCommentVNode(),
/**
* 表体
diff --git a/types/colgroup.d.ts b/types/colgroup.d.ts
index 6917cd057d7aa9c13a7a784d500e77db44d62e70..e3b57c17949f59b321c6cc7984dd7275a94228ca 100644
--- a/types/colgroup.d.ts
+++ b/types/colgroup.d.ts
@@ -64,6 +64,10 @@ export type VxeColgroupProps = {
* 是否可视
*/
visible?: VxeColumnPropTypes.Visible
+ /**
+ * 定制行高
+ */
+ customRowSpan?: VxeColumnPropTypes.CustomRowSpan
/**
* 额外的参数
*/
diff --git a/types/column.d.ts b/types/column.d.ts
index 658eae0f324bae44c7efc42f94267d5f69408ee3..5ba7dd9013acfd1f10fecd096a3a30daf0718a5c 100644
--- a/types/column.d.ts
+++ b/types/column.d.ts
@@ -23,6 +23,7 @@ export namespace VxeColumnPropTypes {
export type Align = 'left' | 'center' | 'right' | null
export type HeaderAlign = Align
export type FooterAlign = Align
+ export type CustomRowSpan = string | number
export type ShowOverflow = VxeTablePropTypes.ShowOverflow
export type ShowHeaderOverflow = ShowOverflow
export type ShowFooterOverflow = ShowOverflow
@@ -159,7 +160,6 @@ export namespace VxeColumnPropTypes {
}
export type Params = any
-
interface FilterSlotParams {
$panel: VxeFilterPanel
column: {
@@ -363,5 +363,9 @@ export type VxeColumnProps = {
/**
* 额外的参数
*/
- params?: VxeColumnPropTypes.Params
+ params?: VxeColumnPropTypes.Params,
+ /**
+ * 定制单元格行高
+ */
+ customRowSpan?: VxeColumnPropTypes.CustomRowSpan,
}
diff --git a/types/table.d.ts b/types/table.d.ts
index ae355128c8f09a190880d223951a05534befccfc..f74555f82dc7c528a9052a0389e1eccb4934da7d 100644
--- a/types/table.d.ts
+++ b/types/table.d.ts
@@ -759,6 +759,8 @@ export interface TableReactData {
parentHeight: number
// 是否使用分组表头
isGroup: boolean
+ // 自定义表头单元格行数
+ useCustomHeaderRowSpan: boolean
isAllOverflow: boolean
// 复选框属性,是否全选
isAllSelected: boolean
@@ -1940,6 +1942,7 @@ export namespace VxeTablePropTypes {
}
export type Params = any
+ export type UseCustomHeaderRowSpan = boolean
}
export type VxeTableProps = {
@@ -2053,6 +2056,7 @@ export type VxeTableProps = {
scrollX?: VxeTablePropTypes.ScrollX
scrollY?: VxeTablePropTypes.ScrollY
params?: VxeTablePropTypes.Params
+ useCustomHeaderRowSpan?: VxeTablePropTypes.UseCustomHeaderRowSpan
}
export type VxeTableEmits = [
@@ -2615,4 +2619,4 @@ export namespace VxeTableEvents {
export type ValidError = (params: VxeTableDefines.ValidErrorEventParams) => void
export type Scroll = (params: VxeTableDefines.ScrollEventParams) => void
export type Custom = (params: VxeTableDefines.CustomEventParams) => void
-}
\ No newline at end of file
+}