您的位置:首页 > Web前端 > JavaScript

纯JS实现排列整齐的数据表格

2016-12-11 18:12 351 查看
本文是在阅读《Eloquent JavaScript》第二版第六章时看到的示例,感觉十分有趣且有代表性,故在此留下笔记。

//1、传入多行,

//2、map遍历每行,返回一个新数组(里面的数组元素个数与行数对应)

//3、reduce计算每行中各个Cell的最大高度,返回一个值(该行的最大高度)

//-->结果得到一个含有每行最大高度的新数组
function rowHeights(rows) {
return rows.map(function(row) {
return row.reduce(function(max, cell) {
return Math.max(max, cell.minHeight());
}, 0);
});
}
//1、传入多行,

//2、根据第一行(row[0])知道当前表格的总列数,并依次作为遍历次数的依据(若rows[0]的列数为3,则遍历3次)

//3、以第2步获得当前列索引(i)为标准,对每行的该列进行比较,比较得出该列的最大宽度(如当前i的值为0,则表示遍历表格各行的第一列)
function colWidths(rows) {
return rows[0].map(function(_, i) {
return rows.reduce(function(max, row) {
return Math.max(max, row[i].minWidth());
}, 0);
});
}
function drawTable(rows) {

var heights = rowHeights(rows);//获取存储某一Cell高和宽的数组
var widths = colWidths(rows);

function drawLine(blocks, lineNo) {
//根据传入的blocks的长度进行遍历,本例中blocks有三列(name、height、country),所以遍历三次
//返回传入的lineNo确定要进行处理的是该Cell的第几行,如该行单元格行数为2,如 name  height country,则lineNo为1时,就是对
//  ----- ------ -------
//name、height、country三个字符串进行处理,最终得到一个新数组["name        ","height","country      "],利用join方法合成为一个字符串,中间加入一个空格" "进行分隔
//即第一行Cell的第一行内容最终输出结果为"name         height country      ",其中name和height之间有13个空格(加上间隔),height和country之间仅一个(country后有六个空格)
return blocks.map(function(block) {
return block[lineNo];
}).join(" ");
}

function drawRow(row, rowNum) {
//对行内Cell进行遍历,得到同行Cell(加入padding后)共同组成的blocks,
//blocks是个二维数组,若该行中的Cell最多有两行,则其表现为[Array[2], Array[2], Array[2]]
var blocks = row.map(function(cell, colNum) {
return cell.draw(widths[colNum], heights[rowNum]);
});
//当前单一Cell占几行,就遍历几次,若该Cell占两行,则lineNo为2,需要调用drawLine两次,
//最终获得一个数组,包含Cell中两行对应的的字符串,用join方法合并为一个字符串,用\n分割换行
return blocks[0].map(function(_, lineNo) {
return drawLine(blocks, lineNo);
}).join("\n");
}
//对所有表格的行进行遍历,得出每行对应的字符串组成的数组,同样用join方法合并为一个字符串
return rows.map(drawRow).join("\n");
}
//用于对不满足所在列最小宽度要求的单元格,加上padding,padding为" "
function repeat(string, times) {
var result = "";
for (var i = 0; i < times; i++)
result += string;
return result;
}
//Cell的构造函数
function TextCell(text) {
this.text = text.split("\n");
}
//返回该Cell里各行中的最大宽度作为该cell的最小行宽
TextCell.prototype.minWidth = function() {
return this.text.reduce(function(width, line) {
return Math.max(width, line.length);
}, 0);
};
//返回该Cell对应的行数(实际上是数组的长度,因为在构造函数中已经用split将字符串变成数组)
TextCell.prototype.minHeight = function() {
return this.text.length;
};
//返回Cell中各行文本在加入padding后组成的数组
TextCell.prototype.draw = function(width, height) {
var result = [];
for (var i = 0; i < height; i++) {
var line = this.text[i] || "";
result.push(line + repeat(" ", width - line.length));
}
return result;
};
//扩展Cell(表头)的构造函数,加入下划线
function UnderlinedCell(inner) {
this.inner = inner;
}
UnderlinedCell.prototype.minWidth = function() {
return this.inner.minWidth();
};
//因为加上下划线有两行,所以高度+1
UnderlinedCell.prototype.minHeight = function() {
return this.inner.minHeight() + 1;
};
UnderlinedCell.prototype.draw = function(width, height) {
return this.inner.draw(width, height - 1)
.concat([repeat("-", width)]);
};

//RTextCell集继承自TextCall,构造函数能让RTextCell继承TextCell的私有属性
function RTextCell(text) {
TextCell.call(this, text);
}
//使用原型链继承,使RTextCell继承TextCell的原型属性
//Object.create能够创建特定原型的实例
RTextCell.prototype = Object.create(TextCell.prototype);
//重写TextCell的draw方法
RTextCell.prototype.draw = function(width, height) {
var result = [];
for (var i = 0; i < height; i++) {
var line = this.text[i] || "";
result.push(repeat(" ", width - line.length) + line);
}
return result;
};
//将对象数组转化为排列整齐的数据表
function dataTable(data) {
//Object.keys方法返回对象包含的(可枚举的)属性数组,因为对象的属性都是相同的,所以只需要数组中的第一个对象即可
var keys = Object.keys(data[0]);
//根据属性数组生成表头
var headers = keys.map(function(name) {
return new UnderlinedCell(new TextCell(name));
});
//遍历各对象
var body = data.map(function(row) {
//遍历对象中的属性数组,根据当前属性值的类型,实例化不同的表格元素(这里的不同指左右对齐)
return keys.map(function(name) {
var value = row[name];
// This was changed:
if (typeof value == "number")
return new RTextCell(String(value));
else
return new TextCell(String(value));
});
});
//最终
return [headers].concat(body);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  javascript