/**
* @module table
* @description 表格
* @property {Array} table 数据源,一个二维数组
* @property {number} fixedColsNum 开始滚动的列,默认为1
* @property {number} tbodyHeight 自定义表体高度
*/
Component({
properties: {
table: { //传入数据源
type: Array,
value: [],
observer: function(newVal, oldVal) {
//属性被设置的时候触发
this.setData({
table: newVal ? newVal : [],
}, () => {
this.ready();
})
//console.log('table', this.data.table);
}
},
fixedColsNum: { //开始滚动的列
type: [Number, String], //可传入数字和数字字符
value: 1,
observer: function(newVal, oldVal) {
//属性被设置的时候触发
this.setData({
fixedColsNum: newVal ? newVal : 1,
}, () => {
this.ready();
})
//console.log('fixedColsNum', this.data.fixedColsNum);
}
},
tbodyHeight: { //表体高度(内部没有使用,所以不用定义到私有)
type: [Number, String],
value: 0,
}
},
data: {
// 数据源,外部传入
table: [],
// 开始滚动的列,可外部传入
fixedColsNum: 1,
// 所有单元格的宽度
colWidths: [],
// 记录滚动位置
scrollTop: 0,
// 根据colWidths获取的总长度
totalWidth: 0,
// 横竖方向都要固定的左上角单元格
fixedCols: [],
// 固定列(除表头)
firstColsOther: [],
// 固定表头(完整)
thead: [],
// 固定表体(完整)
tbody: [],
},
ready: function(e) {
this.ready();
console.log('table_components ready');
},
methods: {
/**
* 滚动时触发,event.detail = {scrollLeft, scrollTop, scrollHeight, scrollWidth, deltaX, deltaY}
*/
scrollVertical: function(event) {
this.setData({
scrollTop: event.detail.scrollTop,
});
},
/**
* 组件的初始化
*/
ready: function() {
const colWidths = this.getColWidths();
const totalWidth = this.getTotalWidth(colWidths);
const fixedCols = this.getFixedCols();
const firstColsOther = this.getFirstColsOther(fixedCols);
const thead = this.getThead();
const tbody = this.getTbody();
this.setData({
colWidths: colWidths,
totalWidth: totalWidth,
fixedCols: fixedCols,
firstColsOther: firstColsOther,
thead: thead,
tbody: tbody,
}, () => {
console.log('table render done')
});
// console.log('colWidths', this.data.colWidths);
// console.log('totalWidth', this.data.totalWidth);
// console.log('fixedCols', this.data.fixedCols);
// console.log('firstColsOther', this.data.firstColsOther);
// console.log('thead', this.data.thead);
// console.log('tbody', this.data.tbody);
},
/**
* 获取固定表头(完整)
*/
getThead: function() {
return this.data.table.length > 0 ? this.data.table[0] : [];
},
/**
* 获取固定表体(完整)
*/
getTbody: function() {
return this.data.table.length > 1 ? this.data.table.slice(1) : [];
},
/**
* 横竖方向都要固定的左上角单元格
*/
getFixedCols: function() {
const result = [];
this.data.table.forEach(row => {
result.push(row
.slice(0, this.data.fixedColsNum)
.map(col => col))
});
return result;
},
/**
* 获取固定列(除表头)
*/
getFirstColsOther: function(fixedCols) {
return fixedCols.length > 1 ? fixedCols.slice(1) : [];
},
/**
* 计算每列的宽度,依据单元格的字符串像素宽度
*/
getColWidths: function() {
const table = this.data.table;
if (table.length === 0) return [];
const result = [];
const TH_FONT_SIZE = 20;
const TD_FONT_SIZE = 24;
const SCALE_RATIO = 1.5;
for (let colIndex = 0, colLen = table[0].length; colIndex < colLen; colIndex++) {
let maxWidth = this.getTextWidth(table[0][colIndex], TH_FONT_SIZE);
for (let rowIndex = 1, rowLen = table.length; rowIndex < rowLen; rowIndex++) {
const cell = table[rowIndex][colIndex];
const cellWidth = this.getTextWidth(cell, TD_FONT_SIZE);
if (cellWidth > maxWidth) {
maxWidth = cellWidth;
}
}
result.push(Math.ceil(maxWidth * SCALE_RATIO));
}
return result;
},
/**
* 获取总长度
*/
getTotalWidth: function(colWidths) {
return colWidths.length > 0 ? colWidths.reduce((acc, cur) => {
return acc + cur
}) : 0;
},
/**
* 根据字符串长度和字体大小计算文本长度,中文为 fontSize,其余为 fontSize / 2
* https://segmentfault.com/a/1190000016405843
* @param {String} text - 文本
* @param {Number} fontSize - 字体大小
* @returns {Number} 长度
*/
getTextWidth: function(text, fontSize) {
text = String(text);
let p = text.split('\n');
let width = 0;
for (let item of p) {
let pStrArr = item.split('');
let pWidth = 0;
for (let f of pStrArr) {
if (new RegExp('[a-zA-Z]').test(f)) {
pWidth += 7;
} else if (new RegExp('[0-9]').test(f)) {
pWidth += 5.5;
} else if (new RegExp('\\.').test(f)) {
pWidth += 2.7;
} else if (new RegExp('-').test(f)) {
pWidth += 3.25;
} else if (new RegExp('[\u4e00-\u9fa5]').test(f)) { // 中文匹配
pWidth += 10;
} else if (new RegExp('\\(|\\)').test(f)) {
pWidth += 3.73;
} else if (new RegExp('\\s').test(f)) {
pWidth += 2.5;
} else if (new RegExp('%').test(f)) {
pWidth += 8;
} else {
pWidth += 10;
}
}
if (pWidth >= width) {
width = pWidth;
}
}
return width * fontSize / 10;
}
}
});