表格
生成一个表示数组数据的文本表格字符串。
特性
安装
npm install table
使用
import { table } from 'table';
// 使用 CommonJS?
// const { table } = require('table');
const data = [
['0A', '0B', '0C'],
['1A', '1B', '1C'],
['2A', '2B', '2C']
];
console.log(table(data));
╔════╤════╤════╗
║ 0A │ 0B │ 0C ║
╟────┼────┼────╢
║ 1A │ 1B │ 1C ║
╟────┼────┼────╢
║ 2A │ 2B │ 2C ║
╚════╧════╧════╝
API
table
返回表格格式的字符串
参数:
-
data: 要显示的数据
- 类型:
any[][]
- 必需:
true
- 类型:
-
config: 表格配置
- 类型:
object
- 必需:
false
- 类型:
config.border
类型:{ [type: string]: string }
默认值:honeywell
模板
自定义边框。键可以是以下任何一个:
topLeft
,topRight
,topBody
,topJoin
bottomLeft
,bottomRight
,bottomBody
,bottomJoin
joinLeft
,joinRight
,joinBody
,joinJoin
bodyLeft
,bodyRight
,bodyJoin
headerJoin
const data = [
['0A', '0B', '0C'],
['1A', '1B', '1C'],
['2A', '2B', '2C']
];
const config = {
border: {
topBody: `─`,
topJoin: `┬`,
topLeft: `┌`,
topRight: `┐`,
bottomBody: `─`,
bottomJoin: `┴`,
bottomLeft: `└`,
bottomRight: `┘`,
bodyLeft: `│`,
bodyRight: `│`,
bodyJoin: `│`,
joinBody: `─`,
joinLeft: `├`,
joinRight: `┤`,
joinJoin: `┼`
}
};
console.log(table(data, config));
┌────┬────┬────┐
│ 0A │ 0B │ 0C │
├────┼────┼────┤
│ 1A │ 1B │ 1C │
├────┼────┼────┤
│ 2A │ 2B │ 2C │
└────┴────┴────┘
config.drawVerticalLine
类型:(lineIndex: number, columnCount: number) => boolean
默认值:() => true
用于决定是否绘制垂直线。此回调函数会为表格的每个垂直边框调用。
如果表格有 n
列,那么 index
参数会依次接收 [0, n]
范围内的所有数字(包括边界值)。
const data = [
['0A', '0B', '0C'],
['1A', '1B', '1C'],
['2A', '2B', '2C'],
['3A', '3B', '3C'],
['4A', '4B', '4C']
];
const config = {
drawVerticalLine: (lineIndex, columnCount) => {
return lineIndex === 0 || lineIndex === columnCount;
}
};
console.log(table(data, config));
╔════════════╗
║ 0A 0B 0C ║
╟────────────╢
║ 1A 1B 1C ║
╟────────────╢
║ 2A 2B 2C ║
╟────────────╢
║ 3A 3B 3C ║
╟────────────╢
║ 4A 4B 4C ║
╚════════════╝
config.drawHorizontalLine
类型:(lineIndex: number, rowCount: number) => boolean
默认值:() => true
用于决定是否绘制水平线。此回调函数会为表格的每个水平边框调用。
如果表格有 n
行,那么 index
参数会依次接收 [0, n]
范围内的所有数字(包括边界值)。
如果表格有 n
行且包含表头,那么范围将是 [0, n+1]
(包括边界值)。
const data = [
['0A', '0B', '0C'],
['1A', '1B', '1C'],
['2A', '2B', '2C'],
['3A', '3B', '3C'],
['4A', '4B', '4C']
];
const config = {
drawHorizontalLine: (lineIndex, rowCount) => {
return lineIndex === 0 || lineIndex === 1 || lineIndex === rowCount - 1 || lineIndex === rowCount;
}
};
console.log(table(data, config));
╔════╤════╤════╗
║ 0A │ 0B │ 0C ║
╟────┼────┼────╢
║ 1A │ 1B │ 1C ║
║ 2A │ 2B │ 2C ║
║ 3A │ 3B │ 3C ║
╟────┼────┼────╢
║ 4A │ 4B │ 4C ║
╚════╧════╧════╝
config.singleLine
类型:boolean
默认值:false
如果设为true
,表格内部的水平线将不会绘制。此选项也会覆盖指定的config.drawHorizontalLine
。
const data = [
['-rw-r--r--', '1', 'pandorym', 'staff', '1529', 'May 23 11:25', 'LICENSE'],
['-rw-r--r--', '1', 'pandorym', 'staff', '16327', 'May 23 11:58', 'README.md'],
['drwxr-xr-x', '76', 'pandorym', 'staff', '2432', 'May 23 12:02', 'dist'],
['drwxr-xr-x', '634', 'pandorym', 'staff', '20288', 'May 23 11:54', 'node_modules'],
['-rw-r--r--', '1,', 'pandorym', 'staff', '525688', 'May 23 11:52', 'package-lock.json'],
['-rw-r--r--@', '1', 'pandorym', 'staff', '2440', 'May 23 11:25', 'package.json'],
['drwxr-xr-x', '27', 'pandorym', 'staff', '864', 'May 23 11:25', 'src'],
['drwxr-xr-x', '20', 'pandorym', 'staff', '640', 'May 23 11:25', 'test'],
];
const config = {
singleLine: true
};
console.log(table(data, config));
╔═════════════╤═════╤══════════╤═══════╤════════╤══════════════╤═══════════════════╗
║ -rw-r--r-- │ 1 │ pandorym │ staff │ 1529 │ May 23 11:25 │ LICENSE ║
║ -rw-r--r-- │ 1 │ pandorym │ staff │ 16327 │ May 23 11:58 │ README.md ║
║ drwxr-xr-x │ 76 │ pandorym │ staff │ 2432 │ May 23 12:02 │ dist ║
║ drwxr-xr-x │ 634 │ pandorym │ staff │ 20288 │ May 23 11:54 │ node_modules ║
║ -rw-r--r-- │ 1, │ pandorym │ staff │ 525688 │ May 23 11:52 │ package-lock.json ║
║ -rw-r--r--@ │ 1 │ pandorym │ staff │ 2440 │ May 23 11:25 │ package.json ║
║ drwxr-xr-x │ 27 │ pandorym │ staff │ 864 │ May 23 11:25 │ src ║
║ drwxr-xr-x │ 20 │ pandorym │ staff │ 640 │ May 23 11:25 │ test ║
╚═════════════╧═════╧══════════╧═══════╧════════╧══════════════╧═══════════════════╝
config.columns
类型:Column[] | { [columnIndex: number]: Column }
列特定配置。
config.columns[*].width
类型:number
默认值:该列的最大单元格宽度
列宽(不包括内边距)。
const data = [
['0A', '0B', '0C'],
['1A', '1B', '1C'],
['2A', '2B', '2C']
];
const config = {
columns: {
1: { width: 10 }
}
};
console.log(table(data, config));
╔════╤════════════╤════╗
║ 0A │ 0B │ 0C ║
╟────┼────────────┼────╢
║ 1A │ 1B │ 1C ║
╟────┼────────────┼────╢
║ 2A │ 2B │ 2C ║
╚════╧════════════╧════╝
config.columns[*].alignment
类型:'center' | 'justify' | 'left' | 'right'
默认值:'left'
单元格内容的水平对齐方式
const data = [
['0A', '0B', '0C', '0D 0E 0F'],
['1A', '1B', '1C', '1D 1E 1F'],
['2A', '2B', '2C', '2D 2E 2F'],
];
const config = {
columnDefault: {
width: 10,
},
columns: [
{ alignment: 'left' },
{ alignment: 'center' },
{ alignment: 'right' },
{ alignment: 'justify' }
],
};
console.log(table(data, config));
╔════════════╤════════════╤════════════╤════════════╗
║ 0A │ 0B │ 0C │ 0D 0E 0F ║
╟────────────┼────────────┼────────────┼────────────╢
║ 1A │ 1B │ 1C │ 1D 1E 1F ║
╟────────────┼────────────┼────────────┼────────────╢
║ 2A │ 2B │ 2C │ 2D 2E 2F ║
╚════════════╧════════════╧════════════╧════════════╝
config.columns[*].verticalAlignment
类型:'top' | 'middle' | 'bottom'
默认值:'top'
单元格内容的垂直对齐方式
const data = [
['A', 'B', 'C', 'DEF'],
];
const config = {
columnDefault: {
width: 1,
},
columns: [
{ verticalAlignment: 'top' },
{ verticalAlignment: 'middle' },
{ verticalAlignment: 'bottom' },
],
};
console.log(table(data, config));
╔═══╤═══╤═══╤═══╗
║ A │ │ │ D ║
║ │ B │ │ E ║
║ │ │ C │ F ║
╚═══╧═══╧═══╧═══╝
config.columns[*].paddingLeft
类型:number
默认值:1
用于在左侧填充内容的空格数。
config.columns[*].paddingRight
类型:number
默认值:1
用于在右侧填充内容的空格数。
paddingLeft
和paddingRight
选项不计入列宽。因此,如果列的width
为5,paddingLeft
为2,paddingRight
为2,那么总宽度将为9。
const data = [
['0A', 'AABBCC', '0C'],
['1A', '1B', '1C'],
['2A', '2B', '2C']
];
const config = {
columns: [
{
paddingLeft: 3
},
{
width: 2,
paddingRight: 3
}
]
};
console.log(table(data, config));
╔══════╤══════╤════╗
║ 0A │ AA │ 0C ║
║ │ BB │ ║
║ │ CC │ ║
╟──────┼──────┼────╢
║ 1A │ 1B │ 1C ║
╟──────┼──────┼────╢
║ 2A │ 2B │ 2C ║
╚══════╧══════╧════╝
config.columns[*].truncate
类型:number
默认值:Infinity
内容将被截断的字符数。
为了处理超出容器宽度的内容,table
包实现了文本换行。然而,有时你可能想要截断太长而无法在表格中显示的内容。
const data = [
['Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pulvinar nibh sed mauris convallis dapibus. Nunc venenatis tempus nulla sit amet viverra.']
];
const config = {
columns: [
{
width: 20,
truncate: 100
}
]
};
console.log(table(data, config));
╔══════════════════════╗
║ Lorem ipsum dolor si ║
║ t amet, consectetur ║
║ adipiscing elit. Pha ║
║ sellus pulvinar nibh ║
║ sed mauris convall… ║
╚══════════════════════╝
config.columns[*].wrapWord
类型:boolean
默认值:false
table
包实现了自动文本换行,即宽度大于容器宽度的文本将在最近的空格或以下特殊字符处分成多行:\|/_.,;-
。
当wrapWord
为false
时:
const data = [
['Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pulvinar nibh sed mauris convallis dapibus. Nunc venenatis tempus nulla sit amet viverra.']
];
const config = {
columns: [ { width: 20 } ]
};
console.log(table(data, config));
╔══════════════════════╗
║ Lorem ipsum dolor si ║
║ t amet, consectetur ║
║ adipiscing elit. Pha ║
║ sellus pulvinar nibh ║
║ sed mauris convallis ║
║ dapibus. Nunc venena ║
║ tis tempus nulla sit ║
║ amet viverra. ║
╚══════════════════════╝
当wrapWord
为true
时:
╔══════════════════════╗
║ Lorem ipsum dolor ║
║ sit amet, ║
║ consectetur ║
║ adipiscing elit. ║
║ Phasellus pulvinar ║
║ nibh sed mauris ║
║ convallis dapibus. ║
║ Nunc venenatis ║
║ tempus nulla sit ║
║ amet viverra. ║
╚══════════════════════╝
config.columnDefault
类型:Column
默认值:{}
所有列的默认配置。特定列的设置将覆盖默认值。
config.header
类型:object
表头配置。
已弃用,推荐使用新的跨越单元格API。
表头配置继承了大部分列的配置,除了:
content
{string}:表头内容。width:
:根据内容宽度自动计算。alignment:
:默认为center
。verticalAlignment:
:不支持。config.border.topJoin
将变为config.border.topBody
以获得更好的外观。
const data = [
['0A', '0B', '0C'],
['1A', '1B', '1C'],
['2A', '2B', '2C'],
];
const config = {
columnDefault: {
width: 10,
},
header: {
alignment: 'center',
content: 'THE HEADER\nThis is the table about something',
},
}
console.log(table(data, config));
╔══════════════════════════════════════╗
║ THE HEADER ║
║ This is the table about something ║
╟────────────┬────────────┬────────────╢
║ 0A │ 0B │ 0C ║
╟────────────┼────────────┼────────────╢
║ 1A │ 1B │ 1C ║
╟────────────┼────────────┼────────────╢
║ 2A │ 2B │ 2C ║
╚════════════╧════════════╧════════════╝
config.spanningCells
类型:SpanningCellConfig[]
跨越单元格配置。
配置应该很直观:只需指定一个包含左上角单元格位置以及从该位置扩展的列数和/或行数的最小单元格配置数组。
重叠单元格的内容将被忽略,以保持data
形状的一致性。
默认情况下,左上角单元格所属列的配置将应用于整个跨越单元格,除了:
width
将是所有跨越列的宽度之和。paddingRight
将有意从最右边的列接收。
可以为每个跨越单元格配置高级自定义列样式,以覆盖默认行为。
const data = [
['Test Coverage Report', '', '', '', '', ''],
['Module', 'Component', 'Test Cases', 'Failures', 'Durations', 'Success Rate'],
['Services', 'User', '50', '30', '3m 7s', '60.0%'],
['', 'Payment', '100', '80', '7m 15s', '80.0%'],
['Subtotal', '', '150', '110', '10m 22s', '73.3%'],
['Controllers', 'User', '24', '18', '1m 30s', '75.0%'],
['', 'Payment', '30', '24', '50s', '80.0%'],
['Subtotal', '', '54', '42', '2m 20s', '77.8%'],
['Total', '', '204', '152', '12m 42s', '74.5%'],
];
const config = {
columns: [
{ alignment: 'center', width: 12 },
{ alignment: 'center', width: 10 },
{ alignment: 'right' },
{ alignment: 'right' },
{ alignment: 'right' },
{ alignment: 'right' }
],
spanningCells: [
{ col: 0, row: 0, colSpan: 6 },
{ col: 0, row: 2, rowSpan: 2, verticalAlignment: 'middle'},
{ col: 0, row: 4, colSpan: 2, alignment: 'right'},
{ col: 0, row: 5, rowSpan: 2, verticalAlignment: 'middle'},
{ col: 0, row: 7, colSpan: 2, alignment: 'right' },
{ col: 0, row: 8, colSpan: 2, alignment: 'right' }
],
};
console.log(table(data, config));
╔════════════════════════════════════════════════════════════════════════════════╗
║ 测试覆盖率报告 ║
╟──────────────┬────────────┬────────────┬──────────┬───────────┬──────────────╢
║ 模块 │ 组件 │ 测试用例 │ 失败数 │ 耗时 │ 成功率 ║
╟──────────────┼────────────┼────────────┼──────────┼───────────┼──────────────╢
║ │ 用户 │ 50 │ 30 │ 3分7秒│ 60.0% ║
║ 服务 ├────────────┼────────────┼──────────┼───────────┼──────────────╢
║ │ 支付 │ 100 │ 80 │ 7分15秒 │ 80.0% ║
╟──────────────┴────────────┼────────────┼──────────┼───────────┼──────────────╢
║ 小计 │ 150 │ 110 │ 10分22秒 │ 73.3% ║
╟──────────────┬────────────┼────────────┼──────────┼───────────┼──────────────╢
║ │ 用户 │ 24 │ 18 │ 1分30秒 │ 75.0% ║
║ 控制器 ├────────────┼────────────┼──────────┼───────────┼──────────────╢
║ │ 支付 │ 30 │ 24 │ 50秒 │ 80.0% ║
╟──────────────┴────────────┼────────────┼──────────┼───────────┼──────────────╢
║ 小计 │ 54 │ 42 │ 2分20秒 │ 77.8% ║
╟───────────────────────────┼────────────┼──────────┼───────────┼──────────────╢
║ 总计 │ 204 │ 152 │ 12分42秒 │ 74.5% ║
╚═══════════════════════════╧════════════╧══════════╧═══════════╧══════════════╝
createStream
table
包导出 createStream
函数用于绘制表格并追加行。
参数:
- config: 与
table
的配置相同,除了config.columnDefault.width
和config.columnCount
必须提供。
import { createStream } from 'table';
const config = {
columnDefault: {
width: 50
},
columnCount: 1
};
const stream = createStream(config);
setInterval(() => {
stream.write([new Date()]);
}, 500);
table
包使用 ANSI 转义码在打印新行时覆盖最后一行的输出。
底层实现在这个 Stack Overflow 回答 中有解释。
流式输出支持静态表格的所有配置属性和功能(如自动文本换行、对齐和填充),例如:
import { createStream } from 'table';
import _ from 'lodash';
const config = {
columnDefault: {
width: 50
},
columnCount: 3,
columns: [
{
width: 10,
alignment: 'right'
},
{ alignment: 'center' },
{ width: 10 }
]
};
const stream = createStream(config);
let i = 0;
setInterval(() => {
let random;
random = _.sample('abcdefghijklmnopqrstuvwxyz', _.random(1, 30)).join('');
stream.write([i++, new Date(), random]);
}, 500);
getBorderCharacters
参数:
- template
- 类型:
'honeywell' | 'norc' | 'ramac' | 'void'
- 必需:
true
- 类型:
你可以使用 getBorderCharacters
函数加载预定义的边框模板之一。
import { table, getBorderCharacters } from 'table';
const data = [
['0A', '0B', '0C'],
['1A', '1B', '1C'],
['2A', '2B', '2C']
];
const config = {
border: getBorderCharacters(`模板名称`)
};
console.log(table(data, config));
# honeywell
╔════╤════╤════╗
║ 0A │ 0B │ 0C ║
╟────┼────┼────╢
║ 1A │ 1B │ 1C ║
╟────┼────┼────╢
║ 2A │ 2B │ 2C ║
╚════╧════╧════╝
# norc
┌────┬────┬────┐
│ 0A │ 0B │ 0C │
├────┼────┼────┤
│ 1A │ 1B │ 1C │
├────┼────┼────┤
│ 2A │ 2B │ 2C │
└────┴────┴────┘
# ramac (ASCII; 用于不支持 Unicode 字符的终端)
+----+----+----+
| 0A | 0B | 0C |
|----|----|----|
| 1A | 1B | 1C |
|----|----|----|
| 2A | 2B | 2C |
+----+----+----+
# void (无边框; 参见文档的"无边框表格"部分)
0A 0B 0C
1A 1B 1C
2A 2B 2C
如果你想贡献新的边框模板,请提出 issue。
无边框表格
简单使用 void
边框字符模板会创建一个有很多不必要空格的表格。
要创建一个更美观的表格,重置填充并移除连接行,例如:
const output = table(data, {
border: getBorderCharacters('void'),
columnDefault: {
paddingLeft: 0,
paddingRight: 1
},
drawHorizontalLine: () => false
}
);
console.log(output);
0A 0B 0C
1A 1B 1C
2A 2B 2C