控制台的艺术(附原理实现)
本文来自网易云社区
作者:黄锴
前言
艺术是孤独的产物,因为孤独比快乐更能丰富人的情感。 ——罗丹
不知道从什么时候开始,人们开始对美的追求从页面转移到了控制台,出现了很多有意思的控制台艺术:
人天生对美的追求,让其不满足于控制台只是黑白和ASCII码的世界,除了使用图案去吸引眼光,颜色也是非常常用的工具,色彩+图案,让原本无聊的控制台慢慢有了生机:
人都是视觉动物,喜欢美的事物,因此一个良好的交互,是非常重要的,在浏览器中,页面是主要的,控制台可能主要是用来吸引程序猿同类,提升程序猿同类对该公司的认同感(哎哟,不错哟,是我的菜)。但是在node环境中,没有页面,控制台就是交互唯一的入口,因此一个优美的控制台环境也是很重要的。
浏览器的样式设计
浏览器端比较简单,根据文档 console.log有一个格式化输出的选项(学过c语言的童鞋对格式化输出应该不陌生),其中有个选项%c就是设置输出样式(css样式,这样可定制化程度应该够用了吧)
占位符 | 含义 |
---|---|
%s | 字符串输出 |
%d or %i | 整数输出 |
%f | 浮点数输出 |
%o | 打印javascript对象,可以是整数、字符串以及JSON数据 |
%c | 样式 |
console.log("%cMy stylish message", "color: red; font-style: italic");console.log("%c3D Text", `text-shadow: 0 1px 0 #ccc,0 2px 0 #c9c9c9,0 3px 0 #bbb,0 4px 0 #b9b9b9,0 5px 0 #aaa,0 6px 1px rgba(0,0,0,.1),0 0 5px rgba(0,0,0,.1),0 1px 3px rgba(0,0,0,.3),0 3px 5px rgba(0,0,0,.2),0 5px 10px rgba(0,0,0,.25),0 10px 10px rgba(0,0,0,.2),0 20px 20px rgba(0,0,0,.15);font-size:5em`);console.log('%cRainbow Text ', `background-image:-webkit-gradient( linear, left top, right top, color-stop(0, #f22),color-stop(0.15, #f2f), color-stop(0.3, #22f), color-stop(0.45, #2ff), color-stop(0.6, #2f2),color-stop(0.75, #2f2), color-stop(0.9, #ff2), color-stop(1, #f22) );color:transparent;-webkit-background-clip: text;font-size:5em;`);console.log("%c\n ", `font-size:140px;background:url('http://o7bk1ffzo.bkt.clouddn.com/20180829153550853783124.png?imageMogr2/thumbnail/750x')no-repeat`);
当然初了样式,控制台还有很多实用的小技巧,例如追踪堆栈信息,分组输出,输出表格,计时,计次……可以参考 这个文章
Node 控制台样式设计
Node由于是运行在后台,它使用的是用户系统的控制台,无法利用浏览器便捷的渲染引擎,因此,它无法实现类似显示图(字符图如果算的话),阴影,边框这么复杂的样式,但是,小改改颜色什么的还是可以的。
毕竟清一色的黑白界面看久了还是会视觉疲劳的,所以现在的一些比较耗时的工具(npm,webpack,glup……)都会用颜色和简单的加载动画去优化用户体验,不让这个等待过程过于枯燥。想想,这和我们在浏览器端优化用户体验的思路不一样的吗?
控制台颜色
原理
不想看原理,想快速的使用的童鞋可以直接往下翻
其实node端的console是可以设置颜色的,这就涉及到linux的颜色转义序列了,最初接触这个东西是PS1中修改字体颜色,其实就是用它来控制linux下控制台输出颜色的,熟悉的人可能还记得:
\e[F;Bm 输入字符串\e[0m
\e 转义字符开始,ESC 的 ASCII 码用十进制表示就是 27,等于用八进制表示的 033。
开始定义颜色。
F' 为字体颜色,编号30~37
B为背景色,编号40~47。
O 为特殊意义代码
m 是标记,后面不用跟空格
前景 | 后景 | 颜色 |
---|---|---|
30 | 40 | 黑色 |
31 | 41 | 红色 |
32 | 42 | 绿色 |
33 | 43 | 黄色 |
34 | 44 | 蓝色 |
35 | 45 | 洋红 |
36 | 46 | 青色 |
37 | 47 | 白色 |
举例,现在你可以直接在控制台输入:
echo -e "\e[37;41m 网易云音乐 \e[0m"
那么接下来,用console来输出颜色就很简单了(注意\x1B就是十六进制的27),借用网上的一个样式表:
console.log('\x1B[31m%s\x1B[0m', '错误'); console.log('\x1B[33m%s\x1b[0m:', '警告'); var styles = { 'bold' : ['\x1B[1m', '\x1B[22m'], 'italic' : ['\x1B[3m', '\x1B[23m'], 'underline' : ['\x1B[4m', '\x1B[24m'], 'inverse' : ['\x1B[7m', '\x1B[27m'], 'strikethrough' : ['\x1B[9m', '\x1B[29m'], 'white' : ['\x1B[37m', '\x1B[39m'], 'grey' : ['\x1B[90m', '\x1B[39m'], 'black' : ['\x1B[30m', '\x1B[39m'], 'blue' : ['\x1B[34m', '\x1B[39m'], 'cyan' : ['\x1B[36m', '\x1B[39m'], 'green' : ['\x1B[32m', '\x1B[39m'], 'magenta' : ['\x1B[35m', '\x1B[39m'], 'red' : ['\x1B[31m', '\x1B[39m'], 'yellow' : ['\x1B[33m', '\x1B[39m'], 'whiteBG' : ['\x1B[47m', '\x1B[49m'], 'greyBG' : ['\x1B[49;5;8m', '\x1B[49m'], 'blackBG' : ['\x1B[40m', '\x1B[49m'], 'blueBG' : ['\x1B[44m', '\x1B[49m'], 'cyanBG' : ['\x1B[46m', '\x1B[49m'], 'greenBG' : ['\x1B[42m', '\x1B[49m'], 'magentaBG' : ['\x1B[45m', '\x1B[49m'], 'redBG' : ['\x1B[41m', '\x1B[49m'], 'yellowBG' : ['\x1B[43m', '\x1B[49m']
成熟工具包
当然,为了实现更加丰富多彩的颜色,还是建议使用现成的包(根据自己的喜欢选择,我选择chalk)
colors :可以实现很复杂的颜色样式
var colors = require('colors');console.log('hello'.green); // outputs green textconsole.log('i like cake and pies'.underline.red) // outputs red underlined textconsole.log('inverse the color'.inverse); // inverses the colorconsole.log('OMG Rainbows!'.rainbow); // rainbowconsole.log('Run the trap'.trap); // Drops the bass
chalk 支持rgb256真彩色,并且写法我更喜欢。
const chalk = require('chalk');const log = console.log;// Combine styled and normal stringslog(chalk.blue('Hello') + ' World' + chalk.red('!'));// ES2015 template literallog(` CPU: ${chalk.red('90%')} RAM: ${chalk.green('40%')} DISK: ${chalk.yellow('70%')} `);// ES2015 tagged template literallog(chalk` CPU: {red ${cpu.totalPercent}%} RAM: {green ${ram.used / ram.total * 100}%} DISK: {rgb(255,131,0) ${disk.used / disk.total * 100}%} `);
加载动画
介绍
我记得大学学C语言的时候,就有一个作业是做控制台动画(正弦余弦波型),还有做控制台游戏“弹球”,就通过利用命令清屏,然后一帧帧重绘出来。
system ('cls')
其实控制台动画,早在1997年就出现了,不知道有没有人看过这个,控制台版的星球大战:
# telnet towel.blinkenlights.nl
还有这个小sl命令的小汽车:
# apt-get install sl (In Debian like OS) # yum -y install sl (In Red Hat like OS) # brew install sl (Max Os)
(如果你想尝试更多,可以参考这篇文章:《20 Funny Commands of Linux or Linux is Fun in Terminal》)
原理
回到我们这边来,node后台处理经常会需要长时间运行的业务(下载远程数据,打包……)这时候,如果这时候控制台直接卡死,用户体验会很糟糕,用户也不知道现在到底在干嘛,所以给一个加载动画是很有必要的。
加载动画的原理也很简单,让我们的数据实在在同一行输出,通过一帧帧图案的替换,实现动画。下面我写了一个简单的实现加载动画和进度条的demo,可以体验一下:
const readline = require("readline");const char = ["◐", "◓", "◑", "◒"];let cur = 0;let info = "loading...";let bar = "[----------------------------]";let done = false;// setInterval(() => {// //删除光标所在行// readline.clearLine(process.stdout);// //移动光标到行首// readline.cursorTo(process.stdout, 0);// cur = (cur + 1) % char.length;// process.stdout.write(char[cur] + " loading...", "utf-8");// }, 200);let timer = setInterval(() => { //删除光标所在行; readline.clearLine(process.stdout); //移动光标到行首 readline.cursorTo(process.stdout, 0); if (done) { info = "done!"; // clearInterval(timer); } process.stdout.write(`${bar} ${info}`, "utf-8"); bar = bar.replace("-", "="); //利用每次只替换一个的原理 if (bar.indexOf("-") < 0) { done = true; } }, 200);
当然,你也可以用single-line-log 去处理。不过现在现成的加载动画的包也很多,就没必要自己手动写了:
成熟的工具包
ora:halk的作者,不愧是控制台艺术的完美饯行者,刚说完他的chalk,又要提他的ora ,这是一个控制台加载动画的包。用法也非常简单(通过start()控制开始,然后在需要结束的时候触发succeed/fail/warn/info函数即可。
const ora = require('ora');const spinner = ora('Loading unicorns').start(); …… spinner.succeed([text]) ……
Node.CLI-Progress 这是一个处理进度条的组件,原理和我上面写的都大同小异,不过包装的十分完善了,感兴趣可以去看看。
字符画(ASCII Art)
介绍
字符画,英文名:zi fu hua~ 开玩笑,字符画专业词汇叫:ASCII Art,最早于1982年(早我出生10年)诞生于卡内基梅隆大学,根据WIkiPedia的解释:
ASCII艺术,又名“文字图”、“字符画”、“文字画”,这种主要依靠计算机表现的艺术形式是指使用计算机字符(主要是ASCII)来表达图片,最早于1982年美国卡内基梅隆大学出>> > 现,互联网刚出现时在英语世界的社交网(Usenet、BITNET、网络论坛、FidoNet、电子布告栏系统BBS)上时常利用到的表情符号。它可以由文本编辑器生成。很多ASCII艺术> 要求使用定宽字体(固定宽度的字体,例如在传统打字机上使用的字体)来显示。
从:-) 到 下面这些例子,都是字符画的表现形式:
HHHHHH HHHHHH IIIIII HHHH HHHH IIII HHHH HHHH IIII HHHHHHHHHHHHHH IIII HHHHHHHHHHHHHH IIII HHHHHHHHHHHHHH IIII HHHH HHHH IIII HHHH HHHH IIII HHHH HHHH IIII HHHHHH HHHHHH IIIIII
成熟工具
这种艺术,如果只凭我们手敲控制,可谓难于上青天,所以需要借助一些现成的生成工具:
Text to ASCII Art Generator 这是一个文字转ASCII码图案的工具,有很多工具的图案就是用这个生成的
Ascii Art Generator 这网站可以把图片转换成ASCII码图案,可以生成纯字符的,也可以生成带颜色字符的,并且可以生成一个
html给你。
……(这类网站实在太多,功能都大同小异)
交互操作
除了显示外,我们还可以加入一些交互式的操作,这个就更复杂了,还好有inquirer 。它提供了很多交互式的操作,关键是它提供了很多插件:单选,时间选择,自动不全,建议,它还有和chalk配合使用的动态字体换色……
反正,这一款足以强大到编写你想要的交互式操作,建立属于自己的CLI!
最后
不管做什么,当你不是把它当作一个机械产物,而是用美的眼光去看待,这件物件便有了温度。
前端作为一个富有创造性和艺术性的职业,虽然不一定能像画家一样做一个美好视觉体验的创造者,但是至少可以当一个美好视觉体验的传递者。
配合颜色和加载字符动画,或者字符画,你的控制台将不再那么单调,至少,让使用者觉得舒服,以下是我现在做的项目的大概输出:
网易云大礼包:https://www.163yun.com/gift
本文来自网易云社区,经作者黄锴授权发布
相关文章:
【推荐】 【专家坐堂】四种并发编程模型简介