zoukankan      html  css  js  c++  java
  • 控制台的艺术(附原理实现)

    本文来自网易云社区

    作者:黄锴

    前言

    艺术是孤独的产物,因为孤独比快乐更能丰富人的情感。 ——罗丹

    不知道从什么时候开始,人们开始对美的追求从页面转移到了控制台,出现了很多有意思的控制台艺术:

    人天生对美的追求,让其不满足于控制台只是黑白和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
           ", `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 是标记,后面不用跟空格

    前景后景颜色
    3040黑色
    3141红色
    3242绿色
    3343黄色
    3444蓝色
    3545洋红
    3646青色
    3747白色

    举例,现在你可以直接在控制台输入:

    echo -e "e[37;41m 网易云音乐 e[0m"


    那么接下来,用console来输出颜色就很简单了(注意x1B就是十六进制的27),借用网上的一个样式表:

    console.log('x1B[31m%sx1B[0m', '错误');  
    console.log('x1B[33m%sx1b[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

    本文来自网易云社区,经作者黄锴授权发布


    相关文章:
    【推荐】 【专家坐堂】四种并发编程模型简介

  • 相关阅读:
    ASP.NET常用信息保持状态学习笔记二
    初识HTTP协议请求与响应报文
    Linux下基于C的简单终端聊天程序
    Linux基于CURSES库下的二维菜单
    aspx与ashx
    linux下基于GTK窗口编程
    ajaxjquery无刷新分页
    asp.net管道模型(管线模型)(内容转载至博客园)
    ASP.NET常用信息保持状态学习笔记一
    ASP.NET使用管道模型(PipleLines)处理HTTP请求 (内容出自CSDN)
  • 原文地址:https://www.cnblogs.com/zyfd/p/9602881.html
Copyright © 2011-2022 走看看