普通开发时并不需要,但有些时候,比如开发了一个脚手架,需要在生成项目时,询问用户这个项目的名称、选用的插件、是否启用某项功能,这些时候就必须要和用户有一些交互了。
inquirer 就是比较好的一项交互工具,下面是他的主要功能。
安装:
npm install inquirer
基本使用:
const inquirer = require('inquirer');
;(async () => {
// 基本用法,传入对象数组,每个对象都是一次提问,按顺序提问
let answers = await inquirer.prompt([
{
type: 'input', // 提示的类型,是 input 输入框
message: '设置一个用户名:', // 要展示的问题提示
name: 'name', // 用于存放用户回答的字段名
default: '小明', // 默认值
},
{
type: 'input', // 提示的类型,是 input 输入框
message: '输入第二个名字:', // 要展示的问题提示
name: 'name2', // 用于存放用户回答的字段名
default: '大明', // 默认值
},
])
// 在 answers 中获取用户应答对象
console.log(answers) // { name: '小明', name2: '大明' }
})()
效果:
数组中每个对象,都是一个问题对象,问题对象中有以下字段:
{
type //(String)提示的类型。默认值:input,可选的值:input,number,confirm,list,rawlist,expand,checkbox,password,editor
name //(String)用于存放用户回答的字段名。
message //(String | Function)要展示的问题提示,如果定义为函数,则第一个参数将是当前查询者会话答案。缺省值为name(后跟冒号)。
default //(String | Number | Boolean | Array | Function)如果未输入任何内容,则使用默认值,或者返回默认值的函数。如果定义为函数,则第一个参数将是当前查询者会话答案。
choices //(Array | Function)choices数组,或返回 choices 数组的函数。如果定义为函数,则第一个参数将是当前查询者会话答案。数组值可以是simple numbers,strings或objects包含name(显示在列表中),value(保存在答案 name 中)和short(选择后显示)属性。choices数组也可以包含一个Separator。
validate //(Function)接收用户输入后的校验函数,入参为用户输入的值,返回true则通过,否则返回错误消息(String),如果返回 false 则显示默认错误消息。
filter //(Function)接收用户输入并回答哈希。返回要在程序内部使用的过滤值。返回的值将添加到Answers哈希中。
transformer //(Function)接收用户输入,回答哈希和选项标志,并返回转换后的值以显示给用户。转换仅影响编辑时显示的内容。它不会修改答案哈希。
when //(Function,Boolean)接收当前用户的答案哈希,并应返回true或false取决于是否应询问此问题。该值也可以是一个简单的布尔值。
pageSize //(Number)改变将使用时呈现的行数list,rawList,expand或checkbox。
prefix //(String)更改默认的前缀消息。
suffix //(String)更改默认的后缀消息。
askAnswered //(Boolean)如果答案已经存在,则强制提示该问题。
loop //(Boolean)启用列表循环。默认值:true。
}
下面开始使用具体例子来讲解。
用于用户输入回车后,进行值的校验,不输入符合规则的值,就会一直卡住。
const inquirer = require('inquirer');
;(async () => {
let answers = await inquirer.prompt([
{
type: 'input',
message: '请输入手机号:',
name: 'phone',
validate: function (val) {
// 校验位数
// 返回 true 则通过
if ((/^\d{11}$/).test(val)) return true;
// 返回其他作为错误提示
// 返回 false,则展示默认错误提示,如果没有,则用户回车后没有任何反应
return '请输入11位数字'
},
},
])
})()
效果:
和 input 类似,只不过这个会把输入的内容自动转为数字。
如果输入的是个非数字,或者无法转成数字,值会变成 NaN。
const inquirer = require('inquirer');
;(async () => {
let answers = await inquirer.prompt([
{
type: 'number',
message: "年龄:",
name: 'num',
default: 18,
},
])
console.log(answers) // { num: 18 }
})()
打印一个询问,用户响应 y 或者 n,来拿到 bool 值。
const inquirer = require('inquirer');
;(async () => {
let answers = await inquirer.prompt([
{
type: 'confirm',
message: '是否同意?',
name: 'agree',
// default: false, // 默认值默认 true,可改为 false
},
])
console.log(answers) // { agree: true }
})()
效果:
提供一个列表给用户,用户使用上下箭头切换,回车选中。
const inquirer = require('inquirer');
;(async () => {
let answers = await inquirer.prompt([
{
type: 'list',
message: '请选择一项',
name: 'checked',
default: '上海', // 默认第一项,可改为其他项
choices: [
'北京',
'上海',
'广州',
],
},
])
console.log(answers) // { checked: '上海' }
})()
效果:
这里插播一条关键点,所有类似 type: "list " 这种需要提供备选列表的问题对象,它提供数组的那一项(大多是 choices 这个字段),可以是字符串数组,也可以是对象数组。
choices 是字符串数组时,default 指定默认值、最终拿到的,都是数组中某一项。
choices 是对象数组时,对象中必须要有 name 字段,作用和字符串数组中的字符串一样。
如果对象还有 value 字段,那 name 字段只用作用户选择时的 label 提示最终值以 value 为准。
如以下例子中的两种方式:
const inquirer = require('inquirer');
;(async () => {
const choices_1 = [ '北京', '上海', '广州' ]
const choices_2 = [
{
name: '北京',
},
{
name: '上海',
value: 'shanghai',
},
{
name: '广州',
value: 'guangzhou',
},
]
let answers = await inquirer.prompt([
{
type: 'list',
message: '请选择一项',
name: 'checked',
default: '北京', // 默认第一项,可改为其他项
choices: choices_1,
// choices: choices_2,
},
])
console.log(answers) // { checked: '上海' }
})()
当 list 列表过于庞大,上下切换太慢,可以提供这种方式,用户可以直接通过输入数字的方式,快速切换。
但最终拿到的对象中的值,仍然是数字中的选项。
const inquirer = require('inquirer');
;(async () => {
let answers = await inquirer.prompt([
{
type: 'rawlist',
message: '请选择一项',
name: 'checked',
default: '上海', // 默认第一项,可改为其他项
choices: [
'北京',
'上海',
'广州',
],
},
])
console.log(answers) // { checked: '上海' }
})()
效果:
上下移动箭头,使用空格键切换是否选中。
const inquirer = require('inquirer');
;(async () => {
let answers = await inquirer.prompt([
{
type: 'checkbox',
message: '请选择一项',
name: 'checked',
default: ['beijing'], // 数组形式
choices: [
{
name: '北京', // 选项的 label,如果没有 value,它将作为最终得到的值
value: 'beijing',
},
new inquirer.Separator(), // 添加分隔符
{
name: '上海',
checked: true, // 默认选中
},
new inquirer.Separator("--- 分隔符 ---"), // 自定义分隔符
{
name: '广州',
value: 'guangzhou',
},
],
},
])
console.log(answers) // { checked: [ 'beijing', '上海' ] }
})()
效果:
输入密码时,输入的字段不会实时打印
const inquirer = require('inquirer');
;(async () => {
let answers = await inquirer.prompt([
{
type: 'password',
message: "请输入密码:",
name: 'pwd',
default: '123456',
},
])
console.log(answers) // { pwd: '123456' }
})()
效果:
偶尔需要用户输入大篇幅需要换行的内容,比如常见的比如 git merge 时,出了不自动合并的冲突,就会出现一个编辑器,让编写信息。
这里也可以:
const inquirer = require('inquirer');
;(async () => {
let answers = await inquirer.prompt([
{
type: 'editor',
message: "请写文章:",
name: 'editor',
},
])
console.log(answers) // { editor: '这是文章\n\n可以进行多行输入\n' }
})()
效果:
也是展示列表供用户选择,但用户交互不太友好,用户不容易懂。
const inquirer = require('inquirer');
;(async () => {
let answers = await inquirer.prompt([
{
type: 'expand',
message: '请选择一项',
name: 'checked',
default: 'shanghai', // 默认第一项,可改为其他项
choices: [
{
key: 'b', // 用户选择时使用,只能单字母
name: '北京', // 用户选择时提示用,如果没有 value 字段,它将作为最终应答的值
value: 'beijing', // 最终应答的值
},
{
key: 's',
name: '上海',
value: 'shanghai',
},
{
key: 'g',
name: '广州',
value: 'guangzhou',
},
],
},
])
console.log(answers) // { checked: 'shanghai' }
})()
效果: