Node.js Color 模塊實現入門淺析
Node.js 中有不少常用的 Color 模塊,例如 chalk 、 colors.js 、 cli-color 等,通過這些模塊我們輸出各種帶顏色、方面區分或者更酷的日志以及 CLI 工具提示。那么今天帶大家簡單了解一下 Color 模塊的實現。
ANSI escape code
與前端上對元素內的文字加上了 CSS 修飾一樣。terminal 中輸出的文字包含顏色也是因為文字的數據跟隨了顏色描述的數據。而要了解 terminal 上的顏色,首先需要了解 ANSI escape code
。
顏色修飾數據對于 terminal 而言,是跟 " \n " 類似的讓顯示出現變化的一種轉義字符。與常見的轉義字符不同,修飾顏色字符(在大部分平臺上)按照 CSI codes 的格式以 " ESC " + " [ " 字符開頭,形如: ESC[ + code1;code2;...;codeN + m 結束(其中的 code 即修飾顏色的數據)。例如:
echo -e "\033[31;42mhello"; # 控制字符[紅色文字;綠色背景結束符號hello
echo -e "\033[0m"; # 重置顏色修飾
echo -e "\033[33mworld"; # 控制字符[黃色文字結束符號world
echo -e "\033[0m"; # 重置顏色修飾
各位用戶(win除外)可以在 terminal 上嘗試一下執行效果,或者使用 Node.js (包括win)運行以下代碼試試:
console.log("\033[31;42mhello"); // 控制字符[紅色文字;綠色背景結束符號hello
console.log("\033[0m"); // 重置顏色修飾
console.log("\033[33mworld"); // 控制字符[黃色文字結束符號world
console.log("\033[0m"); // 重置顏色修飾
執行效果:
注意:ESC 轉義字符在 ASCII 碼中十進制是 27,八進制是 033,十六進制是 0x1B。所以在 Node.js 中除了 \033 之外還可以寫成 \u001b (嚴格模式強制)。
ANSI colors and styles
ANSI 的標準中,特定的 code 表示特定的含義,對于 terminal 的顏色主要有三方面的定義。分別是樣式、顏色、明亮度。
樣式
常見的字體樣式分別是(支持情況視 terminal 而定):
顏色 & 明亮
code 30 - 37 為字體顏色,91 - 97 為字體顏色的明亮版。40 - 47 為背景色,100 - 107 為背景色的明亮版。terminal 的默認字體色 code 是 39,默認背景色是 49。
完整的 code 信息參見 CSI codes 中的 SGR (Select Graphic Rendition) parameters。
Color 模塊實現
了解了 ANSI 編碼中關于顏色部分的知識之后,在 Node.js 中實現一個顏色模塊就很簡單了。
首先我們可以明確一點,跟某段輸出的內容加上顏色,其實要做的事情就是將該內容使用修飾顏色的數據包起來即可。例如輸出一段綠底紅字,相當于輸出 “綠色背景紅色文字修飾數據” + “輸出文字” + “重置修飾”。其效果可以簡單這樣寫:
function getRedTextGreenBg(text) {
return '\033[31;42m' + text + '\033[0m';
}
console.log(getRedTextGreenBg('hello world'));
如果了解 CSI codes 的規則就會發現,對于顏色數據 ESC[ + code1;code2;...;codeN + m 的寫法其實和 ESC[ + code1 + m + ESC[ + code2 + m + ... + ESC[ + codeN + m 的效果是一樣的,目前 Node.js 中大部分 Color 模塊都是按照后者的情況來實現的。
完整一點的 styles 數據可以參考 chalk 的 ansi-styles 。那么我這邊換個簡單的思路模仿 chalk 的調用方式來實現一版,供各位大佬圍觀:
'use strict';
// 嚴格模式要用 unicode 的十六進制不能用八進制的 \033
const styles = {
// style: [ style code, reset code ]
'bold': ['\u001b[1m', '\u001b[22m'],
// ...
'black': ['\u001b[30m', '\u001b[39m'],
'red': ['\u001b[31m', '\u001b[39m'],
'green': ['\u001b[32m', '\u001b[39m'],
'yellow': ['\u001b[33m', '\u001b[39m'],
// ...
'bgBlack': ['\u001b[40m', '\u001b[49m'],
'bgRed': ['\u001b[41m', '\u001b[49m'],
'bgGreen': ['\u001b[42m', '\u001b[49m'],
'bgYellow': ['\u001b[43m', '\u001b[49m'],
// ...
};
const color = {};
Object.keys(styles).map((key) =>
color[key] = (text) =>
styles[key][0] + text + styles[key][1]);
console.log(
color.bgGreen(color.red('hello,')) +
color.yellow(' world!'));
執行效果:
來自:https://zhuanlan.zhihu.com/p/27308276