◆
Node.js inquirer 命令行交互提示用法详解
写脚手架或者构建脚本时,比起让用户记一堆命令行参数,交互式地一问一答更友好——create-vue、vue-cli 那种「请选择要安装的功能」就是这么来的。inquirer 就是做这件事的库:定义一组问题,它负责渲染终端 UI、处理键盘操作,最后把所有答案汇总成一个对象返回。
它的设计是纯声明式的:一个问题就是一个配置对象,type 决定用哪种交互控件,name 决定答案对象里的键。真正让它好用的是几个通用字段——validate 做输入校验、filter 加工答案、when 按前面的回答决定这道题问不问、default 给默认值。有了 when 就能实现分支式的问答流程,而不是一根筋问到底。
下面这段把各类 type 和这几个字段都用了一遍,可以当查阅用的速查表。
inquirer
promptList 是问题数组,按类型分几组看:
input自由文本输入。手机号那题用validate演示校验——返回true通过,返回字符串则把它当错误提示显示出来并要求重新输入(注释里给了正则校验位数的写法)。confirm是 y/n 二选一,答案是布尔值。prefix/suffix是问题文案前后拼接的装饰内容。「是否进行文件过滤」那题的when(answers)是重点:answers里是已经回答过的题,返回false这题就整个跳过——这里只有上一题选了监听才会继续问。- 三种单选各有适用场景:
list是方向键上下移动光标选;rawlist给每项编号、输入数字选;expand用key给每项配一个快捷字符,按键直接命中,适合选项多但常用项固定的场合。list那题的filter演示了答案加工——把选中的Apple转成小写再存进结果。 checkbox多选,答案是数组。choices里可以传对象,用checked: true预选中;插入new inquirer.Separator()画分隔线,构造函数传字符串可以自定义分隔线文案。第二个 checkbox 用pageSize: 2限制一屏显示的行数,超出部分滚动显示,选项很多时避免刷满屏幕。password输入时不回显字符,editor会调起系统默认编辑器(读$EDITOR)写多行内容,适合填备注、commit message 这类长文本。
最后 inquirer.prompt(promptList) 返回 Promise,then 里的 answers 就是以各题 name 为键的答案对象。这里挂在一个 gulp task 上,实际用在 CLI 入口里是一样的写法。
const promptList = [
{
type: 'input',
message: '设置一个用户名:',
name: 'name',
default: 'test_user', // 默认值
},
{
type: 'input',
message: '请输入手机号:',
name: 'phone',
validate(val) {
// if (!val.match(/\d{11}/g)) { // 校验位数
// return '请输入手机号';
// }
return true;
},
},
{
type: 'confirm',
message: '是否使用监听?',
name: 'watch',
prefix: '前缀',
},
{
type: 'confirm',
message: '是否进行文件过滤?',
name: 'filter',
suffix: '后缀',
when(answers) {
// 当watch为true的时候才会提问当前问题
return answers.watch;
},
},
{
type: 'list',
message: '请选择一种水果:',
name: 'fruit',
choices: ['Apple', 'Pear', 'Banana'],
filter(val) {
// 使用filter将回答变为小写
return val.toLowerCase();
},
},
{
type: 'rawlist',
message: '请选择一种水果:',
name: 'fruittwo',
choices: ['Apple', 'Pear', 'Banana'],
},
{
type: 'expand',
message: '请选择一种水果:',
name: 'fruitthree',
choices: [
{
key: 'a',
name: 'Apple',
value: 'apple',
},
{
key: 'O',
name: 'Orange',
value: 'orange',
},
{
key: 'p',
name: 'Pear',
value: 'pear',
},
],
},
{
type: 'checkbox',
message: '选择颜色:',
name: 'color',
choices: [
{
name: 'red',
},
new inquirer.Separator(), // 添加分隔符
{
name: 'blur',
checked: true, // 默认选中
},
{
name: 'green',
},
new inquirer.Separator('--- 分隔符 ---'), // 自定义分隔符
{
name: 'yellow',
},
],
},
{
type: 'checkbox',
message: '选择颜色:',
name: 'colorone',
choices: ['red', 'blur', 'green', 'yellow'],
pageSize: 2, // 设置行数
},
{
type: 'password', // 密码为密文输入
message: '请输入密码:',
name: 'pwd',
},
{
type: 'editor',
message: '请输入备注:',
name: 'editor',
},
];
// 第一步
gulp.task(
'initset',
gulp.series(done => {
inquirer.prompt(promptList).then(answers => {
console.log(answers); // 返回的结果
});
}),
);
注意事项
- inquirer 从 v9 开始是纯 ESM 包,
require('inquirer')会报错。gulpfile 还是 CommonJS 的项目要么锁在 v8,要么改用动态import()。上面这段是 v8 及之前的写法(new inquirer.Separator()这种用法也依赖旧版的 API 形态)。 - 这个 task 里既没 return Promise 也没调
done(),gulp 判断不出任务结束,可能在用户答完题之前就退出了。规范写法是return inquirer.prompt(...)。 validate里要提示错误必须 return 一个字符串,直接console.log会被 inquirer 的 UI 重绘冲掉,看不到。- 交互式提问在 CI 里会直接卡死等输入。脚本要兼顾 CI,得先判断
process.stdout.isTTY,非交互环境下改从命令行参数或环境变量取值。

还没有留言,来发表第一条吧~