编程崽

登录

一叶在编程苦海沉沦的扁舟之上,我是那只激情自射的崽

inquirer 终端中和用户交互

inquirer 终端中和用户交互

普通开发时并不需要,但有些时候,比如开发了一个脚手架,需要在生成项目时,询问用户这个项目的名称、选用的插件、是否启用某项功能,这些时候就必须要和用户有一些交互了。

inquirer 就是比较好的一项交互工具,下面是他的主要功能。

基本使用

安装:

sh 复制代码
npm install inquirer

基本使用:

js 复制代码
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: '大明' }
})()

效果:

Snipaste_2021-04-01_11-05-46.png

数组中每个对象,都是一个问题对象,问题对象中有以下字段:

js 复制代码
{
  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。
}

下面开始使用具体例子来讲解。

input 输入字符串和输入校验

用于用户输入回车后,进行值的校验,不输入符合规则的值,就会一直卡住。

js 复制代码
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位数字'
      },
    },
  ])

})()

效果:

Snipaste_2021-04-01_11-15-40.png

number 输入内容自动转数字类型

和 input 类似,只不过这个会把输入的内容自动转为数字。

如果输入的是个非数字,或者无法转成数字,值会变成 NaN。

js 复制代码
const inquirer = require('inquirer');

;(async () => {

  let answers = await inquirer.prompt([
    {
      type: 'number',
      message: "年龄:",
      name: 'num',
      default: 18,
    },
  ])

  console.log(answers) // { num: 18 }
})()

confirm 询问是否同意

打印一个询问,用户响应 y 或者 n,来拿到 bool 值。

js 复制代码
const inquirer = require('inquirer');

;(async () => {

  let answers = await inquirer.prompt([
    {
      type: 'confirm',
      message: '是否同意?',
      name: 'agree',
      // default: false, // 默认值默认 true,可改为 false
    },
  ])

  console.log(answers) // { agree: true }
})()

效果:

Snipaste_2021-04-01_11-34-25.png

list 单选列表

提供一个列表给用户,用户使用上下箭头切换,回车选中。

js 复制代码
const inquirer = require('inquirer');

;(async () => {

  let answers = await inquirer.prompt([
    {
      type: 'list',
      message: '请选择一项',
      name: 'checked',
      default: '上海', // 默认第一项,可改为其他项
      choices: [
        '北京',
        '上海',
        '广州',
      ],
    },
  ])

  console.log(answers) // { checked: '上海' }
})()

效果:

Snipaste_2021-04-01_11-38-20.png

注意:出现备选列表时,列表的多种书写形式

这里插播一条关键点,所有类似 type: "list " 这种需要提供备选列表的问题对象,它提供数组的那一项(大多是 choices 这个字段),可以是字符串数组,也可以是对象数组。

choices 是字符串数组时,default 指定默认值、最终拿到的,都是数组中某一项。

choices 是对象数组时,对象中必须要有 name 字段,作用和字符串数组中的字符串一样。

如果对象还有 value 字段,那 name 字段只用作用户选择时的 label 提示最终值以 value 为准。

如以下例子中的两种方式:

js 复制代码
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: '上海' }
})()

rawlist 同list,但提供输入序号快捷选择

当 list 列表过于庞大,上下切换太慢,可以提供这种方式,用户可以直接通过输入数字的方式,快速切换。

但最终拿到的对象中的值,仍然是数字中的选项。

js 复制代码
const inquirer = require('inquirer');

;(async () => {

  let answers = await inquirer.prompt([
    {
      type: 'rawlist',
      message: '请选择一项',
      name: 'checked',
      default: '上海', // 默认第一项,可改为其他项
      choices: [
        '北京',
        '上海',
        '广州',
      ],
    },
  ])

  console.log(answers) // { checked: '上海' }
})()

效果:

Snipaste_2021-04-01_11-40-44.png

checkbox 多选

上下移动箭头,使用空格键切换是否选中。

js 复制代码
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', '上海' ] }
})()

效果:

Snipaste_2021-04-01_12-17-53.png

password 输入隐藏形式的密码

输入密码时,输入的字段不会实时打印

js 复制代码
const inquirer = require('inquirer');

;(async () => {

  let answers = await inquirer.prompt([
    {
      type: 'password',
      message: "请输入密码:",
      name: 'pwd',
      default: '123456',
    },
  ])

  console.log(answers) // { pwd: '123456' }
})()

效果:

Snipaste_2021-04-01_13-51-17.png

editor 启用 vim 编辑器进行长文本输入

偶尔需要用户输入大篇幅需要换行的内容,比如常见的比如 git merge 时,出了不自动合并的冲突,就会出现一个编辑器,让编写信息。

这里也可以:

js 复制代码
const inquirer = require('inquirer');

;(async () => {

  let answers = await inquirer.prompt([
    {
      type: 'editor',
      message: "请写文章:",
      name: 'editor',
    },
  ])

  console.log(answers) // { editor: '这是文章\n\n可以进行多行输入\n' }
})()

效果:

Snipaste_2021-04-01_13-58-11.png

expand 自定义字母作为选择(不建议使用)

也是展示列表供用户选择,但用户交互不太友好,用户不容易懂。

js 复制代码
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' }
})()

效果:

Snipaste_2021-04-01_12-10-11.png