直接上代码,下面是组件
继承所有 el-table 的功能和属性 在 mounted 钩子中自动计算列宽 通过分析表头和数据内容计算合适的列宽 支持动态数据更新后的重新计算
<template>
<el-table
ref="table"
v-bind="$attrs"
v-on="$listeners"
>
<slot />
<template v-for="(_, slotName) in $scopedSlots" v-slot:[slotName]="scope">
<slot :name="slotName" v-bind="scope" />
</template>
</el-table>
</template>
<script>
import { Table } from 'element-ui'
export default {
name: 'AutoTable',
inheritAttrs: false,
components: {
ElTable: Table
},
props: {
autoFit: {
type: Boolean,
default: true
},
fontSize: {
type: Number,
default: 14
},
fontRate: {
type: Object,
default: () => ({
CHAR_RATE: 1.2,
NUM_RATE: 0.6,
OTHER_RATE: 0.8
})
}
},
mounted() {
if (this.autoFit) {
this.$nextTick(() => {
this.autoFitColumns()
})
}
},
methods: {
autoFitColumns() {
const table = this.$refs.table
if (!table || !table.data || table.data.length === 0) return
const columns = this.getColumnsConfig()
this.calculateColumnsWidth(columns, table.data)
},
getColumnsConfig() {
return this.$slots.default
.filter(vnode => vnode.componentOptions &&
vnode.componentOptions.tag &&
vnode.componentOptions.tag.endsWith('table-column'))
.map(vnode => {
const props = vnode.componentOptions.propsData || {}
return {
prop: props.prop,
label: props.label,
fixed: props.fixed,
minWidth: props.minWidth,
width: props.width,
fontSize: props.fontSize || this.fontSize,
fontRate: props.fontRate || this.fontRate
}
})
},
calculateColumnsWidth(columns, tableData) {
columns.forEach(column => {
if (column.width || !column.label) return
const values = tableData.map(item => column.prop ? item[column.prop] : '')
const minLength = this.getMaxLength(values, column.fontRate)
const headerLength = column.label.length * column.fontRate.CHAR_RATE
const maxLength = Math.max(minLength, headerLength)
const finalWidth = maxLength * column.fontSize + 40
this.updateColumnWidth(column.prop, Math.ceil(finalWidth))
})
},
getMaxLength(arr, fontRate) {
return arr.reduce((length, item) => {
if (item) {
const str = item.toString()
const char = str.match(/[\u2E80-\u9FFF]/g)
const charLength = char ? char.length : 0
const num = str.match(/\d|./g)
const numLength = num ? num.length : 0
const otherLength = str.length - charLength - numLength
let newLength = charLength * fontRate.CHAR_RATE +
numLength * fontRate.NUM_RATE +
otherLength * fontRate.OTHER_RATE
if (str.includes('\n')) {
newLength = this.getMaxLength(str.split('\n'), fontRate)
}
if (length < newLength) {
length = newLength
}
}
return length
}, 0)
},
updateColumnWidth(prop, width) {
const columns = this.$refs.table.columns
const column = columns.find(col => col.property === prop)
if (column) {
column.width = width
column.realWidth = width
this.$refs.table.doLayout()
}
}
},
watch: {
'$attrs.data'(newVal) {
if (this.autoFit && newVal && newVal.length > 0) {
this.$nextTick(() => {
this.autoFitColumns()
})
}
}
}
}
</script>
使用示例:
<template>
<div>
<auto-table :data="tableData" ref="table">
<el-table-column prop="date" label="日期"> </el-table-column>
......
</auto-table>
</div>
</template>