前言
console.log
对一个前端人,那是在熟悉不过了。我们最经常使用它在控制台输出信息然后进行代码调试,你肯定会发现输出的信息的颜色永远是黑色,当然还有一种我们最不喜欢的颜色 -- 红色,一旦出现了就意味BUG出现了。本文教你如何用 console 在控制台输出五颜六色的信息。
console.log 输出单色的信息
实现起来非常简单,就是 console[1] 能够解析占位符,总的就支持 5 个占位符 %o
,%s
,%s
,%f
,%c
。
其中 %c
指令将 CSS 样式应用于控制台输出,指令前的文本不会受到影响,但指令后的文本将使用参数中的 CSS 声明进行样式设置。
比如想在控制台输出123456
,其中456
的颜色是红色的,可以在控制台中输入以下代码
console.log('123%c456','color: red;')
从上图中可以看到,我们的尝试是有效的,并且表现完全符合预期。
把上面用法封装一下,形成一个“语法糖”,实现如下:
const red = (str)=>{ console.log(`%c${str}`,'color: red') } red('Hello world!')
可以直接复制以上代码到控制台中执行,看是不是效果一样。red
方法就是一个在控制台输出蓝色的信息的语法糖。
其它 4 个占位符,可以翻阅 mozilla console[2] 了解哈。
更灵活的调用 console 方法
通过观察上面的用法,我们发现如果我们需要给同一个字符串添加更多的 CSS 效果,我们需要编辑 log
的第二个参数,而如果需要把两个有颜色的字符串拼接到一起,则需要修改第一参数,并且添加一个第三参数。
console.log(`%c123%c456`,'color: blue;','color: green;')
如果再继续拼接的话,那传入参数更多。在传入参数不确定的时候,我们可以使用 arguments
来获取传入参数,使用 ES6 语法的话,只需要写解构就行。
const log = (...args)=>{ console.log.apply(void 0, args); }
console.log 输出多色的信息
上面实现了单色的信息,那么多色的信息如何实现呢?console.log
在第一个参数后,还可以接受多个参数,每个参数可以给对应的信息设置不同的颜色,具体实现如下:
console.log('%c123%c456','color: blue','color: green')
那如何将 console.log 输出多色的信息封装一下,形成一个"语法糖"呢?
可以这么做,把一个信息拆分成多段,再对应设置不同的颜色,再组合起来 console.log
输出。
比如把 123456
拆分成 123
和 456
,再对应不同的颜色,数据如下所示:
['%c123','color: blue'] ['%c456','color: green']
写一个 add
方法将上面数据拼接成 ['%c123%c456','color: red','color: blue']
,然后利用 apply
调用 console.log
,如下所示:
console.log.apply(void 0, ['%c123%c456','color: blue','color: green']);
复制以上代码到控制台中执行,效果如下图所示:
下面来实现一下 add
方法,并对 console.log
进行二次封装。
const _console = console; const createlog = (util) => (...args) => { const fun = _console[util] ? _console[util] : _console.log; fun.apply(void 0, args); }; const add = (...arr) => { let fi = [[]]; for (let key = 0; key < arr.length; key++) { const [first, ...other] = arr[key]; fi[0] += first; fi = fi.concat(other); } return fi; }; createlog('log')(...add(['%c123','color: blue',],['%c456','color: green']));
复制以上代码到控制台中执行,看一下效果,效果如下图所示:
预设一些颜色值
我们将常用到的一些颜色值,都内置封装一下,方便使用,将上面实现的 red
方法的改造成按这样 chalk.log(chalk.red(123))
调用。
const _console = console; const createlog = (util) => (...args) => { const fun = _console[util] ? _console[util] : _console.log; fun.apply(void 0, args); }; const add = (...arr) => { let fi = [[]]; for (let key = 0; key < arr.length; key++) { const [first, ...other] = arr[key]; fi[0] += first; fi = fi.concat(other); } return fi; }; const chalk = { log:createlog('log') }; const color = { black: '#00000', red: '#FF0000', green: '#008000', yellow: '#FFFF00', blue: '#0000FF', magenta: '#FF00FF', cyan: '#00FFFF', white: '#FFFFFF', }; Object.keys(color).forEach((key) => { chalk[key] = (str) => { // 用户会有两种用法 chalk.red('1231') if (typeof str === 'string' || typeof str === 'number') { return [`%c${str}`, `color:${color[key]}`]; } // 用户第二种用法 chalk.red(chalk.bold('123')) for (let i = 1; i < str.length; i++) { str[i] += `;color:${color[key]}`; } return str; }; }); chalk.log(...add( chalk.black('black'), chalk.red('red'), chalk.green('green'), chalk.yellow('yellow'), chalk.blue('blue'), chalk.magenta('magenta'), chalk.cyan('cyan'), chalk.white('white') ) )
复制以上代码到控制台中执行,看一下效果,效果如下图所示:
增加背景色
通过观察我们发现背景色的方法名,其实就是颜色方法首字母大写再增加 bg
前缀。
简单的修改上面的方法实现
Object.keys(color).forEach((key) => { colorUtils[key] = (str: string | string[]) => { // 用户会有两种用法 chalk.red('1231') if (typeof str === 'string' || typeof str === 'number') { return [`%c${str}`, `color:${color[key]}`]; } // 用户第二种用法 chalk.red(chalk.bold('123')) for (let i = 1; i < str.length; i++) { str[i] += `;color:${color[key]}`; } return str; }; colorUtils[`bg${firstToUpperCase(key)}`] = (str: string | string[]) => { if (typeof str === 'string' || typeof str === 'number') { return [`%c${str}`, `padding: 2px 4px; border-radius: 3px; color: ${key === 'white' ? '#000' : '#fff'}; font-weight: bold; background:${color[key]};`]; } for (let i = 1; i < str.length; i++) { str[i] += `;padding: 2px 4px; border-radius: 3px; font-weight: bold; background:${color[key]};`; } return str; }; });
给日志分级别
为了进一步对日志输出作出更加合理的管控,也为了提供更多的默认颜色输出,因此我们给日志输出划分等级。
const colorHash = { log: 'black', wait: 'cyan', error: 'red', warn: 'yellow', ready: 'green', info: 'blue', event: 'magenta', };
使用这些分级会默认给输出日志添加前缀,如 [Error]
,后面的颜色是默认颜色。
let chalk = {}; if (!window.chalk) { const _console = console; const color = { black: '#000000', red: '#FF0000', green: '#008000', yellow: '#FFFF00', blue: '#0000FF', magenta: '#FF00FF', cyan: '#00FFFF', white: '#FFFFFF', }; const add = (...arr) => { let fi = [ [] ]; for (let key = 0; key < arr.length; key++) { const [first, ...other] = arr[key]; fi[0] += first; fi = fi.concat(other); } return fi; }; const createlog = (util) => (...args) => { const fun = _console[util] ? _console[util] : _console.log; fun.apply(void 0, args); }; const colorUtils = { bold: (str) => { if (typeof str === 'string' || typeof str === 'number') { return `${str};font-weight: bold;`; } for (let key = 1; key < str.length; key++) { str[key] += `;font-weight: bold;`; } return str; } }; const colorHash = { log: 'black', wait: 'cyan', error: 'red', warn: 'yellow', ready: 'green', info: 'blue', event: 'magenta', }; const createChalk = (name) => (...str) => { if (typeof str[0] === 'object') { createlog(name)(...add(colorUtils.bold(colorUtils[colorHash[name]](`[${firstToUpperCase(name "colorHash[name]")}] `)), ...str)); return; } let strArr = str; if (typeof str === 'string' || typeof str === 'number') { strArr = colorUtils[colorHash[name]](str "colorHash[name]"); } createlog(name)(...add(colorUtils.bold(colorUtils[colorHash[name]](`[${firstToUpperCase(name "colorHash[name]")}] `)), strArr)); }; const chalk = {}; Object.keys(colorHash).forEach(key => { chalk[key] = createChalk(key); }); const firstToUpperCase = (str) => str.toLowerCase().replace(/( |^)[a-z]/g, (L) => L.toUpperCase()); Object.keys(color).forEach(key => { colorUtils[key] = (str) => { if (typeof str === 'string' || typeof str === 'number') { return [`%c${str}`, `color:${color[key]}`]; } for (let i = 1; i < str.length; i++) { str[i] += `;color:${color[key]}`; } return str; }; colorUtils[`bg${firstToUpperCase(key)}`] = (str) => { if (typeof str === 'string' || typeof str === 'number') { return [`%c${str}`, `padding: 2px 4px; border-radius: 3px; color: ${key === 'white' ? '#000' : '#fff'}; font-weight: bold; background:${color[key]};`]; } for (let i = 1; i < str.length; i++) { str[i] += `;padding: 2px 4px; border-radius: 3px; font-weight: bold; background:${color[key]};`; } return str; }; }); window.chalk = { add, ...chalk, ...colorUtils, }; } chalk = window.chalk; chalk.log('log'); chalk.error('error'); chalk.warn('warn')
自定义定制函数
熟练的上述的方法之后,你就可以随意的添加你需要的函数了,比如常见的打印框架的版本号。
const hello = (title: string, version: string) => createlog('log')( `%c ${title} %c V${version} `, 'padding: 2px 1px; border-radius: 3px 0 0 3px; color: #fff; background: #606060; font-weight: bold;', 'padding: 2px 1px; border-radius: 0 3px 3px 0; color: #fff; background: #42c02e; font-weight: bold;', ); hello('Malita','0.0.6');
比如打印图片
const image = (img: string) => createlog('log')(`%c `, `font-size: 1px; padding: 100px 100px; background-image: url(${img}); background-size: contain; background-repeat: no-repeat; color: transparent;`); image('https://logo.png')
当然你也可以输出动图。只要你熟练掌握了这些方法,你就可以随意的发挥你的创意。
灵感来源
以上实现的灵感来源于一个很流行的 node 控制台美化仓库,chalk[3],它在 GitHub 上拥有 18.3k 的 star。
import chalk from 'chalk'; console.log(chalk.blue('Hello world!'));
在项目中使用
为了方便大家和我自己使用,我将这个功能发布到了 npm 上,你可以在你的项目中使用。
npm i @alita/chalk
import chalk from '@alita/chalk'; window.alitadebug = true; chalk.hello('Malita','0.0.6'); // 或者 import '@alita/chalk'; window.alitadebug = true; window.chalk.hello('Malita','0.0.6');
我增加了一个日志开关 window.alitadebug = true;
,好处就是部署上线的代码,正常情况下不打印日志,如果出现错误需要定位代码,可以直接通过控制台中输入 window.alitadebug = true;
来开启。
源码开源[4]
21天挑战手写前端框架系列[5]
感谢阅读,如果你觉得这个东西很有趣,或者你有好的创意,欢迎在评论区和我互动。
参考资料
[1]
console: https://developer.mozilla.org/en-US/docs/Web/API/console#examples
[2]
mozilla console: https://developer.mozilla.org/en-US/docs/Web/API/console#examples
[3]
chalk: https://github.com/chalk/chalk
[4]
源码开源: https://github.com/alitajs/alita/tree/master/packages/chalk
[5]
21天挑战手写前端框架系列: https://juejin.cn/column/7084812367116107789