Appearance
命令行美化:chalk 与 ora
命令行工具的用户体验不仅取决于功能是否完善,视觉呈现同样重要。想象一下:当执行一个耗时操作时,如果终端毫无反馈,用户会以为程序卡住了;当输出一堆无差别的白色文字时,用户很难快速定位关键信息。
本章介绍两个解决这些问题的核心工具:
- chalk:为终端输出添加颜色,让成功、警告、错误一目了然
- ora:显示加载动画,让用户知道程序正在工作
为什么需要颜色
人类视觉系统对颜色非常敏感。在信息密集的终端输出中:
- 红色立即吸引注意力 → 用于错误
- 绿色传递积极信号 → 用于成功
- 黄色警示但不紧急 → 用于警告
- 蓝色/灰色辅助信息 → 用于提示
这不是装饰,而是信息设计。
chalk 基础
bash
npm install chalk版本说明:chalk v5+ 是 ESM-only,CommonJS 项目请使用
npm install chalk@4
javascript
const chalk = require('chalk');
// 颜色即语义
console.log(chalk.red('错误信息')); // 出错了
console.log(chalk.green('成功信息')); // 操作成功
console.log(chalk.yellow('警告信息')); // 需要注意
console.log(chalk.blue('提示信息')); // 普通信息颜色和样式
前景色
chalk 支持 16 种基础颜色。选择颜色时考虑其语义含义:
javascript
// 常用颜色(有明确语义)
console.log(chalk.red('红色')); // 错误、危险
console.log(chalk.green('绿色')); // 成功、安全
console.log(chalk.yellow('黄色')); // 警告、注意
console.log(chalk.blue('蓝色')); // 信息、链接
console.log(chalk.gray('灰色')); // 次要信息
// 其他颜色(装饰性)
console.log(chalk.magenta('品红'));
console.log(chalk.cyan('青色'));
console.log(chalk.white('白色'));背景色
背景色用于强调特别重要的信息,但要谨慎使用——过多的背景色会让界面混乱:
javascript
console.log(chalk.bgRed('红色背景')); // 严重错误
console.log(chalk.bgGreen('绿色背景')); // 重要成功
console.log(chalk.bgYellow.black('黄色背景黑字')); // 注意文字颜色对比度样式
样式可以独立使用或与颜色组合:
javascript
console.log(chalk.bold('粗体')); // 强调
console.log(chalk.dim('暗淡')); // 次要信息
console.log(chalk.italic('斜体')); // 引用、注释
console.log(chalk.underline('下划线')); // 链接
console.log(chalk.inverse('反色')); // 高亮选中
console.log(chalk.strikethrough('删除线')); // 废弃内容链式调用
chalk 的强大之处在于可以链式组合多种样式。注意组合时的可读性:
javascript
console.log(chalk.red.bold('红色粗体')); // 严重错误
console.log(chalk.bgBlue.white.bold('蓝底白字粗体')); // 标题
console.log(chalk.green.underline('绿色下划线')); // 成功的链接模板字符串
javascript
console.log(`
${chalk.green('✓')} 安装成功
${chalk.red('✗')} 安装失败
${chalk.yellow('!')} 警告
`);日志工具封装
javascript
const chalk = require('chalk');
const log = {
info: (msg) => console.log(chalk.blue('ℹ'), msg),
success: (msg) => console.log(chalk.green('✓'), msg),
warn: (msg) => console.log(chalk.yellow('⚠'), msg),
error: (msg) => console.log(chalk.red('✗'), msg)
};
log.info('开始处理...');
log.success('处理完成');
log.warn('文件已存在');
log.error('发生错误');ora 加载动画
bash
npm install ora版本说明:ora v6+ 是 ESM-only,CommonJS 项目请使用
npm install ora@5
javascript
const ora = require('ora');
// 创建并启动 spinner
const spinner = ora('加载中...').start();
// 2秒后显示成功状态
setTimeout(() => {
spinner.succeed('加载完成'); // 替换动画为 ✓
}, 2000);工作原理:ora 通过不断更新同一行内容来实现动画效果。它使用 ANSI 转义码控制光标位置,这也是为什么它只能在支持 ANSI 的终端中正常工作。
spinner 状态
spinner 有多种结束状态,表达不同的操作结果:
javascript
const ora = require('ora');
async function process() {
const spinner = ora('下载中...').start();
try {
await download();
spinner.succeed('下载完成'); // 操作成功
} catch (err) {
spinner.fail('下载失败'); // 操作失败
}
}状态方法详解
每个状态会停止动画并显示对应图标:
javascript
spinner.start('开始处理'); // ⏳ 开始动画
spinner.stop(); // 停止,不显示任何图标
spinner.succeed('成功'); // ✓ 绿色勾
spinner.fail('失败'); // ✗ 红色叉
spinner.warn('警告'); // ⚠ 黄色警告
spinner.info('信息'); // ℹ 蓝色信息最佳实践:始终用状态方法结束 spinner,否则动画会一直运行。
更新文本
长时间操作时,可以动态更新提示文本让用户了解进度:
javascript
const spinner = ora('步骤 1/3: 下载依赖...').start();
setTimeout(() => {
spinner.text = '步骤 2/3: 编译代码...'; // 更新文本,动画继续
}, 1000);
setTimeout(() => {
spinner.text = '步骤 3/3: 生成文档...';
}, 2000);
setTimeout(() => {
spinner.succeed('全部完成'); // 停止动画
}, 3000);自定义 spinner
javascript
const spinner = ora({
text: '处理中...',
spinner: 'dots', // 动画类型
color: 'cyan'
}).start();可用的动画类型:dots, dots2, line, star, hamburger, balloon 等。
组合使用
javascript
const chalk = require('chalk');
const ora = require('ora');
async function deploy() {
console.log(chalk.bold('\n🚀 开始部署\n'));
// 步骤 1
const build = ora('构建项目...').start();
await sleep(1500);
build.succeed('构建完成');
// 步骤 2
const upload = ora('上传文件...').start();
await sleep(2000);
upload.succeed('上传完成');
// 步骤 3
const restart = ora('重启服务...').start();
await sleep(1000);
restart.succeed('服务已重启');
console.log(chalk.green.bold('\n✓ 部署成功!\n'));
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
deploy();进度条
使用 cli-progress:
bash
npm install cli-progressjavascript
const cliProgress = require('cli-progress');
const bar = new cliProgress.SingleBar({
format: '进度 |{bar}| {percentage}% | {value}/{total}',
barCompleteChar: '█',
barIncompleteChar: '░'
});
bar.start(100, 0);
let value = 0;
const timer = setInterval(() => {
value += 10;
bar.update(value);
if (value >= 100) {
clearInterval(timer);
bar.stop();
console.log('\n完成!');
}
}, 200);完整示例
javascript
const chalk = require('chalk');
const ora = require('ora');
const cliProgress = require('cli-progress');
async function install() {
console.log(chalk.bold.cyan('\n📦 安装依赖\n'));
const packages = ['express', 'lodash', 'axios', 'dayjs', 'uuid'];
const bar = new cliProgress.SingleBar({
format: `${chalk.cyan('{bar}')} {percentage}% | {package}`,
barCompleteChar: '█',
barIncompleteChar: '░',
hideCursor: true
});
bar.start(packages.length, 0, { package: '' });
for (let i = 0; i < packages.length; i++) {
bar.update(i + 1, { package: packages[i] });
await sleep(500);
}
bar.stop();
console.log(chalk.green('\n✓ 安装完成!\n'));
console.log(chalk.gray('已安装的包:'));
packages.forEach(pkg => {
console.log(` ${chalk.green('+')} ${pkg}`);
});
console.log();
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
install();chalk v5+ (ESM)
新版本使用 ESM:
javascript
import chalk from 'chalk';
console.log(chalk.red('错误'));CommonJS 项目使用 v4:
bash
npm install chalk@4本章小结
- chalk 提供彩色输出,支持链式调用
- ora 显示加载动画,支持多种状态
- cli-progress 显示进度条
- 组合使用提升用户体验
- 注意 ESM/CommonJS 兼容性
下一章我们将学习文件批处理实战。