基于inquirer实现一个控制台多级选择交互功能

news2025/2/27 17:22:40

说在前面

🎈在前端脚手架工具中经常会看到控制台输入参数等操作。例如Vue-cli中初始化项目会提示选择一些参数等。所以在开发脚手架工具或者node控制台程序,就需要用到inquirer工具或者类似的工具。但是使用过inquirer工具的同学应该知道,目前inquirer工具支持的交互方式只有以下几种:input, number, confirm, list, rawlist, expand, checkbox, password, editor,最近自己在封装一个脚手架工具时需要使用到多级选择的功能来进行交互,但是看了一遍inquirer的文档,发现并没有可以直接使用的多级选择器类型交互,于是便开始基于inquirer进行二次封装,实现多级选择交互的功能。

效果展示

配置好参数后直接运行,效果如下图👇

在这里插入图片描述

实现思路

功能分解

首先我们先来分解一下这个功能,我们拥有一份树级结构的数据:

{
    'aa': [ 'aaa1', 'aaa2', 'aaa3', 'aaa4' ],
    'bb': [ 'bbb1', 'bbb2' ],
    'cc': [ 'ccc1' ]
}

我们需要实现以下这几个功能:

  • 1、按级展示对应的数据

接收的参数数据应该为树级结构的数据,我们应该对其进行分级展示(像电脑上的文件目录层级一样)。

  • 2、非叶子级的节点点击应该可以下钻

对于非叶子级的节点(及当前节点拥有子节点),我们对其点击应该进行下钻并展示其子节点的数据。

  • 3、叶子节点可以多选

遍历到叶子级别的数据时,我们需要支持多选功能。

  • 4、跨父节点数据保持

当我们进入一个叶子层级并进行了选择之后,我们还需要返回进入其他层级进行选择,这时我们需要保存在不同层级下选中的数据内容。

功能实现

将功能分解成几个小点之后,我们便可以按照分解好的功能点来逐点实现:

  • 1、按级展示对应的数据

这一点的功能其实就是一个单选选择框的功能,我们发现这点可以直接使用inquirer中类型为list的组件来实现。

const options = [{
    type: 'list',
    name: 'choice',
    message: 'your choice:',
    default: 0,
    choices: [
        { value: 1, name: '张三' },
        { value: 2, name: '李四' }
    ]
}];
const j = new JInquirer(options);
const res = j.prompt().then(res=>{
    console.log(res);
});

运行的结果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xo1ZhUCX-1668566115879)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/922dda3d632a48c09de9c7c7d9dee17b~tplv-k3u1fbpfcp-watermark.image?)]

这里我们只需要将传入的树级结构数据遍历到的层级的key提出重新组成list的参数即可:

//叶子节点层级的数据应该为数组类型的数据,所以可以通过isArray来判断当前层级是否为叶子层级
optionTemp.type = Array.isArray(obj) ? 'checkbox' : 'list';
optionTemp.choices = Array.isArray(obj) ? obj : Object.keys(obj);
  • 2、非叶子级的节点点击应该可以下钻

遍历到非叶子层级时,我们需要递归处理其子级节点数据,非叶子层级的列表我们使用的是list单选列表来展示,叶子层级的数据我们使用的是checkbox多选列表来展示,所以我们可以根据当前展示的类别来进行不同的递归处理。

(1)非叶子层级

对于非叶子层级的数据,我们点击应该进入下一级:

await this.chooseExpandList(op,deep + 1,pre+answer[option.name],originOption);

(2)叶子层级

对于叶子层级的数据,我们选择完成后应该回到根节点级别继续选择:

await this.chooseExpandList(originOption,0,'',originOption);

完整关键代码如下:

if(optionTemp.type === 'list'){
    if(pre) pre += '/';
    const op = {...option};
    op.choices = obj[answer[option.name]];
    await this.chooseExpandList(op,deep + 1,pre+answer[option.name],originOption);
}else{
    this.tempList[pre] = answer[option.name];
    await this.chooseExpandList(originOption,0,'',originOption);
}
  • 3、叶子节点可以多选

叶子节点列表我们需要支持多选功能,这个功能我们可以直接复用inquirer中类型为checkbox的复选框来实现。

const options1 = [{
    type: 'checkbox',
    name: 'choice',
    message: 'your choice:',
    default: 0,
    choices: [
        { value: 1, name: '张三' },
        { value: 2, name: '李四' }
    ]
}];
const j = new JInquirer(options1);
const res = j.prompt().then(res=>{
    console.log(res);
});

运行结果如下图:

在这里插入图片描述

可以使用空格进行选择,ctrl + a 可以全选,ctrl + i 进行反选,回车确认选择内容。

  • 4、跨父节点数据保持

这里我们可以使用两个方案来实现:

(1)使用函数入参来记录选中的数据

我们可以将每次选中的数据在函数的入参中传入,每次回调时更新该参数即可。

(2)在类中添加一个参数来记录。

直接在类中添加一个公共参数来记录,这样读取会比较方便。

比较了两种方法后,我觉得还是直接在类中添加一个公共参数来记录,这样读取会比较方便,所以最后选择了使用方案二来实现该功能。

class JInquirer{
    constructor(options,config){
        this.options = options; //参数
        this.config = config || {}; //配置
        this.answer = {}; //输出结果容器
        this.tempList = {}; //中间值临时容器变量
    }
}

使用方法

1、安装依赖

npm install @jyeontu/j-inquirer

2、在代码中引用

const JInquirer = require('@jyeontu/j-inquirer');

3、示例代码

const options1 = [{
        type:"input",
        message:"请输入你的姓名:",
        name:"name",
        notNull:true
    },{
    type: 'expandList',
    name: 'choice',
    message: '多级选择器测试:',
    choices:{
        'aa': [ 'aaa1', 'aaa2', 'aaa3', 'aaa4' ],
        'bb': [ 'bbb1', 'bbb2' ],
        'cc': [ 'ccc1' ]
      }
}];
const j = new JInquirer(options1);
const res = j.prompt().then(res=>{
    console.log(res);
});

源码地址

https://gitee.com/zheng_yongtao/node-scripting-tool/tree/master/src/JInquirer

觉得有帮助的同学可以帮忙给我点个star,感激不尽~~~
有什么想法或者改良可以给我提个pr,十分欢迎~~~
有什么问题都可以在评论告诉我~~~

往期精彩

面试官:不使用canvas怎么实现一个刮刮卡效果?

vue封装一个3D轮播图组件

vue实现一个鼠标滑动预览视频封面组件(精灵图版本)

node封装一个图片拼接插件

基于inquirer封装一个控制台文件选择器

node封装一个控制台进度条插件

密码太多不知道怎么记录?不如自己写个密码箱小程序

微信小程序实现一个手势图案锁组件

vue封装一个弹幕组件

为了学(mo)习(yu),我竟开发了这样一个插件

程序员的浪漫之——情侣日常小程序

vue简单实现词云图组件

说在后面

🎉这里是JYeontu,喜欢算法,GDCPC打过卡;热爱羽毛球,大运会打过酱油。毕业一年,两年前端开发经验,目前担任H5前端开发,算法业余爱好者,有空会刷刷算法题,平时喜欢打打羽毛球🏸 ,也喜欢写些东西,既为自己记录📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解🙇,写错的地方望指出,定会认真改进😊,在此谢谢大家的支持,我们下文再见🙌。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/9664.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringSecurity整合SSM和SpringBoot完成方法级权限控制

初识权限管理 权限管理,一般指根据系统设置的安全规则或者安全策略,用户可以访问而且只能访问自己被授权的资源。权限管理几乎出现在任何系统里面,前提是需要有用户和密码认证的系统。 在权限管理的概念中,有两个非常重要的名词&…

SpringBoot SpringBoot 开发实用篇 1 热部署 1.4 关闭热部署功能

SpringBoot 【黑马程序员SpringBoot2全套视频教程,springboot零基础到项目实战(spring boot2完整版)】 SpringBoot 开发实用篇 文章目录SpringBootSpringBoot 开发实用篇1 热部署1.4 关闭热部署功能1.4.1 关闭热部署1.4.2 小结1.4.3 总结1 …

大佬神作!Spring Security从应用到源码,这份手册都讲全了,已三刷

简介 平时我们写 Web 项目,都需要用户登录时验证,以及权限管理之类的操作,以前使用过滤器,拦截器等进行管理,原生代码较多。 所以出现了安全框架以供我们使用,安全框架在 Web 应用的主要功能是&#xff1a…

金九失足,10月喜提“Java高分指南”,11月冲击大厂

蓦然回首自己做开发已经十年了,这十年中我获得了很多,技术能力、培训、出国、大公司的经历,还有很多很好的朋友。但再仔细一想,这十年中我至少浪费了五年时间,这五年可以足够让自己成长为一个优秀的程序员,…

VS2017安装教程(详细版)

1.首先下载好安装包 百度网盘下载链接 链接:https://pan.baidu.com/s/1HW8hrLMazRsBkPvkDHkD1Q?pwdz4jg 提取码:z4jg 2.下载到桌面以管理员身份运行 点击继续 3.进入后更改安装位置,选择安装路径,千万不要安装到C盘 4.改完后…

Opencv——直方图、掩膜、直方图均衡化详细介绍及代码实现

一、图像直方图 1.1 定义: 图像直方图是图像的基本属性之一,也是反映图像像素数据分布的统计学特征,其横坐标代表了图像像素点在[0,255]范围中,纵坐标代表图像像素点出现的个数或百分比。如图: 1.2 函数:…

Go程序内存泄露问题快速定位

前几天有同学反馈了 cgo 内存泄露问题,自己也针对这个问题探索了一番,算是为以后解决类似问题提前攒点经验吧。也趁机整理了一下 go 开发过程中内存泄露问题的一些常用排查方法,也希望对新接触 go 的同学有所帮助。整理之余,bcc 工…

面试问题:MD5属于哪种加密算法?千万别踩这些坑

一些小伙伴吐槽,去面试的时候经常听到面试官问这样的问题,“对称加密”、“非对称加密”、“MD5加密”,那么MD5到底属于哪种加密算法?遇到这样的问题,一定要小心,这是面试官给你挖的坑呢,可别傻…

C++——pair用法总结

C——pair用法总结1.pair概述&#xff08;在标头 <utility> 定义&#xff09;2.pair使用2.1成员函数&#xff08;构造函数、赋值函数&#xff09;2.2非成员函数2.3辅助类使用1.pair概述&#xff08;在标头 定义&#xff09; std::pair 是类模板&#xff0c;提供在一个单…

Kotlin MVVM之Jetpack系列ViewModel、LiveData的简单使用

一、MVVM是什么&#xff1f; MVVM分为Model&#xff0c;View&#xff0c;ViewModel 三个部分 Model:数据层&#xff0c;包含数据实体和对数据实体的操作 View:UI层&#xff0c;对应于Activity&#xff0c;XML&#xff0c;负责数据显示以及用户交互。 ViewModel&#xff1a;…

22-Redux-1

//npm init //npm install redux //1 导入redux&#xff08;不能通过es6的方式&#xff09; // commonjs一种 -> node.jsconst redux require(redux)const initialState {counter: 0 } // reducer function reducer(state initialState, action) {switch(action.type) {c…

5 步!用阿里云 Serverless 搭建高质量的图片压缩工具

作者&#xff1a;Regan Yue 本文选自“Serverless 函数计算征集令”活动 什么是 Serverless Serverless 是一种基于云计算的开发方法&#xff0c;它让开发人员可以专注于编写代码来解决业务问题&#xff0c;而不是处理服务器问题。它是独一无二的&#xff0c;因为它支持 Auto …

Rust中级教程:指针生态(引用、原始指针、智能指针)and内存操作(Stack、Heap)

指针的一些概览知识点 1.内存地址&#xff1a;指代内存中单个字节的一个整数。 指针&#xff08;原始指针&#xff09;&#xff1a;就是指向某种类型的一个内存地址。 引用&#xff1a;就是指针&#xff0c;是rust提供的一种抽象&#xff0c;如果是动态大小&#xff0c;就是一…

标记肽MGP-7-氨基-4-甲基香豆素、1926163-53-2、Met-Gly-Pro-AMC

蛋氨酸氨基肽酶1D和2的荧光底物。编号: 152397 中文名称: 标记肽MGP-7-氨基-4-甲基香豆素 英文名: H-Met-Gly-Pro-AMC CAS号: 1926163-53-2 单字母: H2N-MGP-AMC 三字母: H2N-Met-Gly-Pro-AMC 氨基酸个数: 3 分子式: C22H28N4O5S1 平均分子量: 460.55 精确分子量: 460.18 等电点…

【SVN】SVN服务端地址变动,idea切换SVN地址

公司切换了SVN服务端的制度&#xff0c;需要本地对应切换SVN地址&#xff0c;以下为具体步骤 错误方式 直接 项目上右键 --> Subversion --> Relocate &#xff0c;修改 To URL 的值&#xff0c;会报错 https://XXXXX is not the root of the repository 的错误 正确的…

Communication-Efficient Learning of Deep Networks from Decentralized Data

international conference on artificial intelligence and statistics Summary 当前机器学习模型训练中存在着数据隐私保护问题&#xff0c;所以作者提出了FL概念。通过分布式隐私保护进行训练模型。对不平衡、non-IID的数据也更合适。 主要提出了FedSGD和FedAvg算法。FedAv…

Andriod开发R文件爆红相关解决方法及排查方案

1.首先尝试下基本的处理方法&#xff1a; 在IDE中工具栏处选择build 尝试clean project&#xff0c;然后再进行rebuild project或者是make project 若使用的是IDEA或Android studio&#xff0c;在上述方法尝试后可以尝试工具栏中File->Setting->Invalidate Caches/Rest…

微信小程序(基础语法)

文章目录基本组件视图容器viewscroll-viewswiper和swiper-item基础内容组件textrich-text其他常用组件buttonimagenavigator基本模板数据绑定插值表达式事件绑定常用事件在事件处理函数中为data的数据赋值事件传参bindinput的使用小程序中的v-model条件渲染wx:ifhidden列表渲染…

一些关于通信拓扑、图论的内容笔记

链接&#xff1a;https://zhuanlan.zhihu.com/p/373368383 目前主要是这一个系列&#xff0c;记下来怕我过后忘了。 别处看到的&#xff08;大概率3B1B&#xff09;----走桥的问题----d偶数 多智能体一致性问题&#xff08;分蛋糕&#xff09; 入度 出度 &#xff1a;信息流…

007_补充_ Pytorch 反向传播和Neural ODE的反向传播

一、Pytorch反向传播 首先是第一个小例子&#xff0c;训练模型拟合 y true_w * x true_b&#xff0c;模型的参数为 param_w, param_b import torchtrue_w torch.Tensor([[2.0, 3.0], [4.0, 5.0]]) # 初始化真实的参数 true_b torch.Tensor([[1.0, 2.0], [3.0, 4.0]]) #…