基于inquirer封装一个控制台文件选择器
说在前面
我们在用脚手架初始化项目的时候,往往会进行一些命令交互,用过vue或者react的用脚手架新建项目的应该都进行过命令交互,vue创建的时候会让你选择vue2还是vue3,也有多选要什么配置,也有输入y或者n选择是否用history路由等,这些简单的交互其实用inquire这个包都能实现,但是最近自己在做一个小工具的时候,想要进行文件和文件夹的选择,这时我发现inquire里并没有这个交互功能,所以便自己尝试去在inquire这个库的基础上实现文件选择和文件夹选择这两种类型的交互。
插件效果
通过该插件,我们可以在控制台通过方向键来选择文件和文件夹,具体效果如下:
插件实现
Inquirer.js
Inquirer.js试图为NodeJs做一个可嵌入式的美观的命令行界面。如下图:
inquirer原有参数
- type
表示提问的类型,包括:input、confirm、 list、rawlist、expand、checkbox、password、editor。
- name
存储当前输入的值。
- message
问题的描述。
- default
默认值。
- choices
列表选项,在某些type下可用,并且包含一个分隔符(separator);
- validate
对用户的回答进行校验。
- filter
对用户的回答进行过滤处理,返回处理后的值。
- when
根据前面问题的回答,判断当前问题是否需要被回答。
- pageSize
修改某些type类型下的渲染行数。
- prefix
修改message默认前缀。
- suffix
修改message默认后缀。
二次封装
基于inquirer原有功能及参数,增加一些扩展功能及参数
新增参数
- notNull
是否不能为空,默认为false,设置为true后该参数不能输入空,并且会有不能为空的提示,必须输入字符后才可以回车确认并进行下一步,如下图:
{type:"input",message:"请输入你的姓名:",name:"name",notNull:true
}
- type
在原有类型中新增两种类型:file、folder,分别为文件选择器和目录选择器,效果如下图:
{type:"file",message:"请选择文件:",name:"fileName",default:"",
},
{type:"folder",message:"请选择文件夹:",name:"folderName",default:"",pathType:'absolute'
},
- pathType
此项为新增配置,设置目录和文件选择器选中路径输出的格式,默认为相对路径,可以设置为absolute,此时会输出绝对路径,效果如下图:
{type:"file",message:"请选择文件:",name:"fileName",default:"",
},
{type:"folder",message:"请选择文件夹:",name:"folderName",default:"",pathType:'absolute'
},
代码实现
获取指定路径下的文件列表
使用fs
中的readdirSync
方法可以获取指定目录下的文件列表,具体代码如下:
getFileList = (dirPath)=>{const list = fs.readdirSync(dirPath);return ['../(返回上一级)',...list];
}
获取指定路径下的目录列表
使用fs
中的readdirSync
方法可以获取指定目录下的文件列表,通过isDirectory
方法可以判断文件是否为目录文件,具体代码如下:
getFolderList = (dirPath)=>{const list = fs.readdirSync(dirPath);let resList = [];list.map(item=>{const fullPath = path.join(dirPath,item);if(fs.statSync(fullPath).isDirectory()){resList.push(item + '(进入文件夹)');resList.push(item + '(选择文件夹)');}});return ['../(返回上一级)',...resList];
}
交互类型响应控制
新增的file
和folder
类型使用自己重新封装的方法,其他依旧使用Inquirer中的响应方法,具体代码如下:
run(option){if(option.type === 'file'){return this.chooseFile(option);}else if(option.type === 'folder'){return this.chooseFolder(option);}else{if(option.notNull){const flag = option.message.slice(-1);if([":",":"].includes(flag)){option.message = option.message.slice(0,-1) + '(不能为空)' + flag;}}return this.defaultType(option);}
}
选择文件
- 选择的为
返回上一级
,则将当前目录回退一级:
this.clear(2);
return this.chooseFile(option,path.join(dirPath,'/../'));
- 选择的是目录则进入选择的目录:
return path.join(dirPath, answer[option.name]);
- 选择的是文件则返回选择的文件路径并结束操作:
this.clear(2);
return this.chooseFile(option,fullPath);
- 完整代码如下
chooseFile(option,dirPath = './'){option.type = 'list';option.suffix = "(当前浏览目录:" + path.join(__dirname,dirPath) + ')';option.pageSize = fs.readdirSync('./').length + 1;option.choices = [...this.getFileList(dirPath)];const answer = await inquirer.prompt([option]);if(answer[option.name] == '../(返回上一级)'){this.clear(2);return this.chooseFile(option,path.join(dirPath,'/../'));}else{const fullPath = path.join(dirPath, answer[option.name]);if(!fs.statSync(fullPath).isFile()){this.clear(2);return this.chooseFile(option,fullPath);}else{return path.join(dirPath, answer[option.name]);}}
}
选择目录
- 选择的为
返回上一级
,则将当前目录回退一级:
this.clear(2);
return this.chooseFile(option,path.join(dirPath,'/../'));
- 选择的是进入文件夹,则进入该目录,这里需要将加入用于区分的后缀去掉再返回:
return path.join(dirPath, answer[option.name].slice(0,-7));
- 选择的是选择文件夹则返回选择的文件夹路径并结束操作:
this.clear(2);
return this.chooseFile(option,fullPath);
- 完整代码如下
chooseFile(option,dirPath = './'){option.type = 'list';option.suffix = "(当前浏览目录:" + path.join(__dirname,dirPath) + ')';option.pageSize = fs.readdirSync('./').length + 1;option.choices = [...this.getFileList(dirPath)];const answer = await inquirer.prompt([option]);if(answer[option.name] == '../(返回上一级)'){this.clear(2);return this.chooseFile(option,path.join(dirPath,'/../'));}else{const fullPath = path.join(dirPath, answer[option.name]);if(!fs.statSync(fullPath).isFile()){this.clear(2);return this.chooseFile(option,fullPath);}else{return path.join(dirPath, answer[option.name]);}}
}
基本类型调用Inquirer处理
这里增加了notNull
(是否不能为空)的参数,代码如下:
defaultType(option){const answer = await inquirer.prompt([option]);if(option.notNull && answer[option.name] === ''){this.clear(2);return this.defaultType(option);}return answer[option.name];
}
插件使用
1、安装依赖
npm install @jyeontu/j-inquirer
2、在代码中引用
const JInquirer = require('@jyeontu/j-inquirer');
3、示例代码
const JInquirer = require('@jyeontu/j-inquirer');
let options = [{type:"input",message:"请输入你的姓名:",name:"name",notNull:true},{type:"input",message:"请输入你的年龄:",name:"age",default:18,validate:(val)=>{if(val < 0 || val > 150){return "请输入0~150之间的数字";}return true;}},{type:"file",message:"请选择文件:",name:"fileName",default:"",},{type:"folder",message:"请选择文件夹:",name:"folderName",default:"",pathType:'absolute'},{type:"list",message:"请选择你喜欢的水果:",name:"fruit",default:"Apple",choices:["Apple","pear","Banana"],},{type:"expand",message:"请选择一个颜色:",name:"color",default:"red",choices:[{key : 'R',value : "red"},{key : 'B',value : "blue"},{key : 'G',value : "green"}]},{type:"checkbox",message:"选择一至多种颜色:",name:"color2",choices:["red","blue","green","pink","orange"]},{type:"password",message:"请输入你的密码:",name:"pwd"},{type:"editor",message:"写下你想写的东西:",name:"editor"}
];
let j = new JInquirer(options);
let res = j.prompt().then(res=>{console.log(res);
});
源码地址
https://gitee.com/zheng_yongtao/node-scripting-tool/tree/master/src/JInquirer
觉得有帮助的同学可以帮忙给我点个star,感激不尽~~~
有什么想法或者改良可以给我提个pr,十分欢迎~~~
有什么问题都可以在评论告诉我~~~
往期精彩
node封装一个控制台进度条插件
vue实现一个鼠标滑动预览视频封面组件
密码太多不知道怎么记录?不如自己写个密码箱小程序
微信小程序实现一个手势图案锁组件
vue封装一个图案手势锁组件
vue封装一个弹幕组件
为了学(mo)习(yu),我竟开发了这样一个插件
程序员的浪漫之——情侣日常小程序
vue简单实现词云图组件
vue + echarts实现中国地图省份下钻联动
使用学过的算法做个游戏很酷的好吗
说在后面
基于inquirer封装一个控制台文件选择器相关推荐
- 基于 element-plus 封装一个依赖 json 动态渲染的查询控件
前情回顾 优惠券网站 m.cps3.cn 基于 el-form 封装一个依赖 json 动态渲染的表单控件 Vue3 封装第三方组件(一)做一个合格的传声筒 功能 使用 vue3 + element- ...
- 基于iview 封装一个vue 表格分页组件
iview 是一个支持中大型项目的后台管理系统ui组件库,相对于一个后台管理系统的表格来说分页十分常见的 iview是一个基于vue的ui组件库,其中的iview-admin是一个已经为我们搭好的后天 ...
- 基于Vue3封装一个好用的Websocket
在Vue3中使用Websocket可以让我们轻松地实现实时数据传输.为了方便使用,我们可以封装一个好用的Websocket类. 安装依赖 首先我们需要安装 ws 库来处理Websocket连接,使用以 ...
- formdata上传文件_封装一个多文件断点续传、分片上传、秒传、重试机制的组件...
本文为:多文件断点续传.分片上传.秒传.重试机制 的更新版,若想看初始版本的实现,请查看该文章. 凡是要知其然知其所以然 文件上传相信很多朋友都有遇到过,那或许你也遇到过当上传大文件时,上传时间较长, ...
- 分享基于silverlight的一个大文件上传控件
虽然codeplex已经有一些多文件,带进度条的上传控件,但是觉得都不是很好用,所以基于上面的控件重新设计了一个上传控件,更好的交互,属性绑定和管理文件. 1. 客户端使用: <mycontro ...
- QT基于QPolarChart封装一个极坐标系类(控件显示)
1.首先需要下载相应的QChart库 一般在安装QT时会选择此库,如若没有,请自行下载. 2.在工程文件中添加:QT += charts 3.新建一个极坐标系的封装类PolarChart: 4.头文件 ...
- 封装一个操作文件的函数
#一个函数只做一件事 def my_file(name,content=None): with open(name,'a+') as f: f.seek(0) if content: f.write( ...
- 基于 jQuery 与 Bootstrap 简单封装一个表格分页的组件
最近遇到一个需求:页面上的数据可能会有很多条,需要将数据分页展示在表格中.项目用的是 jQuery 和 Bootstrap,本来想直接用 bootstrapTable 插件,但是需要额外引入 js 文 ...
- 如何基于HTTP设计一个加密解密系统
在基于B/S 的业务系统中,如果要设计开发加密解密机制.有几种设计选型: 可以使用现成的HTTPS 架构,后端部署用知名签名机构生成的证书. 可以使用现成的HTTPS 架构,后端部署自签名的证书,但是 ...
最新文章
- 【串讲总结】RNN、LSTM、GRU、ConvLSTM、ConvGRU、ST-LSTM
- 100999凑整到万位进一_四年级数学专项练习
- 内存总是不够?HBaseGeoMesa配置优化了解一下
- 梯度的直观理解_BP反向传播算法的思考和直观理解 -卷积小白的随机世界
- java怎么将图片文件转流并在jsp前端显示_jsp已经被淘汰了吗?
- 大数据_Flink_流式处理_简介_流数据处理的应用行业---Flink工作笔记0003
- IDEA----将本地svn项目导入idea后没有拉取提交按钮
- 四阶五级matlab,微分方程数值解法matlab(四阶龙格—库塔法).ppt
- ApacheCN 翻译/校对/笔记整理活动进度公告 2019.9.13
- AI不仅要智能,更需要人文:联邦学习重构大数据风控范式
- 传统企业PaaS平台功能设计与业务上云思考
- 图的遍历——深度优先搜索和广度(宽度)优先搜索(含例题)
- arm poky linux,交叉编译iMX6 contex-A9 arm-poky 一些坑
- 二维我的世界Dev c++代码
- DataGrip 连接 Hive 1.1
- 多元高斯分布(Multivariate Gaussian Distribution)(详细说明,便于理解)
- 博士申请 | 香港中文大学(深圳)语音与语言实验室招收Speech/NLP方向全奖博士生...
- (8)雅思屠鸭第八天:听力中最重要的179个单词(必知必会)
- 触摸屏TP基础学习笔记资料整理
- 【svn】sliksvn下载与安装
热门文章