自定义组件源码
<template>
<el-table-column
v-if="$scopedSlots.default"
v-bind="$attrs"
:label="label"
:prop="prop"
:min-width="minWidth || calculWidth(listFieldName)"
:formatter="formatter"
>
<template slot-scope="scope">
<slot v-bind="scope" />
</template>
</el-table-column>
<el-table-column
v-else
v-bind="$attrs"
:label="label"
:prop="prop"
:min-width="minWidth || calculWidth(listFieldName)"
:formatter="formatter"
/>
</template>
<script>
export default {
name: "RyTableColumn",
props: {
label: {
default: "",
type: [String, Number],
},
prop: {
default: "",
type: String,
},
// 自定义最小宽度(可选)
minWidth: {
default: "",
type: [String, Number],
},
// 自定义最大宽度(可选)
maxWidth: {
default: "",
type: [String, Number],
},
// 自定义在数组列表中的字段名(可选)
listFieldName: {
default: "",
type: String,
},
// 自定义需要计算宽度的字符串(可选)
widthStr: {
default: "",
type: String,
},
// 自定义格式化方法(可选)
formatter: {
default: null,
type: Function,
},
// 计算过滤器返回值的宽度(可选)
widthFilter: {
default: "",
type: String,
},
},
data() {
return {};
},
created() {},
methods: {
calculWidth(listFieldName) {
const { getStrWidth, maxWidth } = this;
const labelStr = this.label + "WWW";
// 获取源数据数组
const listData = this.$parent.data ? this.$parent.data : [];
// 设置宽度初始值
let width = !this.widthStr ? getStrWidth(labelStr) : getStrWidth(this.widthStr);
if (!this.widthStr && ((this.prop && !this.widthFilter) || this.formatter)) {
const fieldName = listFieldName || this.prop;
if (listData.length > 0) {
// formatter方法
const formatterFun = this.formatter;
listData.forEach((item) => {
// 计算每行宽度
const itemWidth = formatterFun ? getStrWidth(formatterFun(item)) : getStrWidth(item[fieldName]);
width = Math.max(itemWidth, width);
});
}
} else if (this.widthStr) {
// 包含花括号
const reBracketContentIn = /\{(.+?)\}/g;
// 不包含花括号
const reBracketContentEx = /(?<=\{)(.+?)(?=\})/g;
const bracketContentArr = this.widthStr.match(reBracketContentEx);
if (bracketContentArr) {
width = getStrWidth(labelStr);
listData.forEach((listItem) => {
let arrIndex = 0;
let repContentArr = [];
// 获取需要赋值的数组
bracketContentArr.forEach((bItem, bIndex) => {
for (const field in listItem) {
if (bItem == field) {
repContentArr[bIndex] = listItem[field];
}
}
})
// 字符串相应位置替换为数组中对应的值
const repWidthStr = this.widthStr.replace(reBracketContentIn, () => {
const resStr = repContentArr[arrIndex]
arrIndex++;
return resStr;
})
width = Math.max(getStrWidth(repWidthStr), width);
});
}
} else if (this.widthFilter) {
// 包含中括号
const reBracketContentIn = /\[(.+?)\]/g;
// 不包含中括号
const reBracketContentEx = /(?<=\[)(.+?)(?=\])/g;
const bracketContentArr = this.widthFilter.match(reBracketContentEx);
if (bracketContentArr) {
listData.forEach((row) => {
let arrIndex = 0;
let repContentArr = [];
bracketContentArr.forEach((item) => {
const filterFun = this.$options.filters[item.split("|")[1].trim()];
const paramName = item.split("|")[0].trim();
const resField = filterFun(row[paramName])
repContentArr.push(resField);
})
const repWidthFilterStr = this.widthFilter.replace(reBracketContentIn, () => {
const resStr = repContentArr[arrIndex]
arrIndex++;
return resStr;
})
width = Math.max(getStrWidth(repWidthFilterStr), width);
})
} else {
const filterFun = this.$options.filters[this.widthFilter.split("|")[1].trim()];
const paramName = this.widthFilter.split("|")[0].trim();
listData.forEach((row) => {
const resField = filterFun(row[paramName])
width = Math.max(getStrWidth(resField), width);
})
}
}
return maxWidth && (width > maxWidth) ? maxWidth : Math.max(100, width);
},
// 获取字符串中的字符数量
getCharNumber(charType, str) {
if (!charType || !str) {
return 0;
}
str = str.toString();
let resNum = 0;
let inArr;
switch (charType) {
// 中文字符
case "zh":
resNum = str.match(/[\u4E00-\u9FA5]/g) ? str.match(/[\u4E00-\u9FA5]/g).length : 0;
break;
// 英文大写字符
case "enUp":
resNum = str.match(/[\A-Z]/g) ? str.match(/[\A-Z]/g).length : 0;
break;
// 英文小写字符
case "enLow":
resNum = str.match(/[\a-z]/g) ? str.match(/[\a-z]/g).length : 0;
break;
// 数字字符
case "num":
resNum = str.match(/[0-9]/g) ? str.match(/[0-9]/g).length : 0;
break;
// 短字符
case "short":
resNum = str.match(/[:;'.,!*|]/g) ? str.match(/[:;'.,!*|]/g).length : 0;
break;
// 其他字符
case "other":
inArr = str.match(/[\u4E00-\u9FA5\A-Z\a-z0-9:;'.,!*|]/g);
resNum = str.length - (inArr ? inArr.length : 0);
break;
default:
resNum = 0;
}
return resNum;
},
// 计算字符串长度
getStrWidth(str) {
if (!str) {
return 0;
}
str = str.toString();
// 每个中文字符占用宽度
const zhPerWidth = 18.8;
// 每个英文大写字符占用宽度
const enUpPerWidth = 11;
// 每个英文小写字符占用宽度
const enLowPerWidth = 8.5;
// 每个数字字符占用宽度
const numPerWidth = 11;
// 每个短字符占用宽度
const shortPerWidth = 6;
// 每个其他字符占用宽度
const otherPerWidth = 12;
const colZhLenWidth = this.getCharNumber("zh", str) * zhPerWidth;
const colEnUpLenWidth = this.getCharNumber("enUp", str) * enUpPerWidth;
const colEnLowLenWidth = this.getCharNumber("enLow", str) * enLowPerWidth;
const colNumLenWidth = this.getCharNumber("num", str) * numPerWidth;
const colShortLenWidth = this.getCharNumber("short", str) * shortPerWidth;
const colOtherLenWidth = this.getCharNumber("other", str) * otherPerWidth;
return colZhLenWidth + colEnUpLenWidth + colEnLowLenWidth + colNumLenWidth + colShortLenWidth + colOtherLenWidth;
},
},
};
</script>
<style lang="scss" scoped>
</style>
简单说明
基本原理为根据内容中中文字符和其他字符的长度计算需要占用的宽度
标签内可用属性
1、格式化(自动计算格式化后的字符串长度):
:formatter="(row)=>{return row.cardId + 'WWwww'}"
2、过滤器(自动计算过滤器结果字符串的长度,只支持全局过滤器):
width-filter="createDate | getDateTimeFn1"
可支持多个过滤器:
width-filter="[createDate | getDateTimeFn1] [createDate | getDateTimeFn1]"
3、自定义用来计算宽度的字符串,按照配置的内容计算宽度:
:width-str="' '+$t('preDepositAcct.list.modify')+$t('cardManagement.delete')"
4、增加原组件不支持的最大宽度的配置:
max-width="200"