纯JS实现排列整齐的数据表格
2016-12-11 18:12
351 查看
本文是在阅读《Eloquent JavaScript》第二版第六章时看到的示例,感觉十分有趣且有代表性,故在此留下笔记。
//1、传入多行,
//2、map遍历每行,返回一个新数组(里面的数组元素个数与行数对应)
//3、reduce计算每行中各个Cell的最大高度,返回一个值(该行的最大高度)
//-->结果得到一个含有每行最大高度的新数组
//2、根据第一行(row[0])知道当前表格的总列数,并依次作为遍历次数的依据(若rows[0]的列数为3,则遍历3次)
//3、以第2步获得当前列索引(i)为标准,对每行的该列进行比较,比较得出该列的最大宽度(如当前i的值为0,则表示遍历表格各行的第一列)
//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); }
相关文章推荐
- JQuery1——基础($对象,选择器,对象转换)
- Android学习笔记(二九):嵌入浏览器
- Android java 与 javascript互访(相互调用)的方法例子
- 只需四个步骤几行代码,即可快速实现直播弹幕功能
- JavaScript演示排序算法
- javascript实现10进制转为N进制数
- JavaScript 基础、进阶以及 Ubuntu 系统中的 JavaScript 开发调试工具
- 最后一次说说闭包
- Ajax
- 2019年开发人员应该学习的8个JavaScript框架
- HTML中的script标签研究
- 对一个分号引发的错误研究
- 设计模式---状态模式在web前端中的应用
- 异步流程控制:7 行代码学会 co 模块
- ES6 走马观花(ECMAScript2015 新特性)
- JavaScript拆分字符串时产生空字符的原因
- Canvas 在高清屏下绘制图片变模糊的解决方法