前端架构: 脚手架命令行交互核心实现之inquirer和readline的应用教程

本文主要是介绍前端架构: 脚手架命令行交互核心实现之inquirer和readline的应用教程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

命令行交互核心实现

  • 核心目标:实现命令行行交互,如List
  • 命令行的交互呢比命令行的渲难度要更大,因为它涉及的技术点会会更多
  • 它涉及以下技术点
    • 键盘输入的一个监听 (这里通过 readline来实现)
    • 计算命令行窗口的尺寸
    • 清屏
    • 光标的移动
    • 输出流的静默 (我们输出的内容, 不让它去输出到当前的这个终端中)
    • 借助输入输出流,引出输入输出流的一个监听以及事件库 events
    • ansi escaped code 转义字符
  • 命行交互其实是有一定复杂度的, 在这个过程中,最重点的库和命行交互最重点库是两个 readlineinquirer

inquirer

  • inquirer 是一个命令行交互常用的库,Weekly Downloads 30,375,340 (动态数据)
  • 作为一个命令行交互的库能做到这个程度,可以说是非常的不简单,而且一直在持续的进行维护,目前已经达到9.2.15版本了
  • 安装 $ npm i -S inquirer
  • 使用示例1:input类型演示
    import inquirer from 'inquirer';
    inquirer.prompt([{type: 'input',name: 'yourName',message: 'your name:',}]).then((answers) => {console.log(answers);}).catch((error) => {if (error.isTtyError) {// Prompt couldn't be rendered in the current environment} else {// Something else went wrong}});
    
    • 这里根据文档上的框架结构
    • 通过 type, name, message 三个字段即可完成初始化创建
    • 更多,参考文档:https://www.npmjs.com/package/inquirer#question
效果实例
  • 另外,比较常用的还有
    • default 默认值字段
    • validate 字段是一个回调
      • 用于对字段的校验,只有校验返回 true的时候校验才会结束
    • transformer 字段用于处理信息展示的回调
      • 也就是这个函数内部返回的值是展示的值
      • 返回的值还是之前的 name 字段
      • 更多的像是表单中的 placeholder 仅作为展示
    • filter 字段是一个回调
      • 它会最终改变 answers 最终的结果
      • 会最终改变 name 字段
  • 其他: choice 在匹配 List 列表的时候会用到
  • 注意,prompt 方法内部接受的是一个数组,可以写多个对象来收集数据
  • 使用示例2: 多字段演示
    import inquirer from 'inquirer';inquirer.prompt([{type: 'input',name: 'yourName',message: 'your name:',default: 'Lee',validate: function(v) {return v === 'Wang'},transformer: function(v) {return 'your input name: ' + v // 仅作为展示},filter: function(v) {return v;// return v + '123' // 改变最终值}},{type: 'number', // 这种,在没有 validate 的情况下,如果输入的是非数字, 会变成 NaNname: 'num',message: 'your number',},// ...]).then((answers) => {console.log(answers); // 最终打印的是一个对象,多个字段}).catch((error) => {if (error.isTtyError) {// Prompt couldn't be rendered in the current environment} else {// Something else went wrong}});
    
    • 在示例1中已做了详细说明,这里不再赘述
效果实例
  • 使用示例3: confirm 类型演示
    import inquirer from 'inquirer';inquirer.prompt([{type: 'confirm', // 二选一功能name: 'choice',message: 'your choice:',default: false,},]).then((answers) => {console.log(answers);}).catch((error) => {if (error.isTtyError) {// Prompt couldn't be rendered in the current environment} else {// Something else went wrong}});
    
效果实例
  • 使用示例4: list 类型演示
    import inquirer from 'inquirer';inquirer.prompt([{type: 'list', // 列表单选name: 'choice',message: 'your choice:',default: 0, // 这里 default 是 下面choices 的索引choices: [{value: 1, name: 'LiLy'},{value: 2, name: 'Lucy'},{value: 3, name: 'Lee'},]},]).then((answers) => {console.log(answers);}).catch((error) => {if (error.isTtyError) {// Prompt couldn't be rendered in the current environment} else {// Something else went wrong}});
    
效果实例
  • 使用示例5: expend 类型演示
    import inquirer from 'inquirer';inquirer.prompt([{type: 'expand', // 简写选择name: 'choice',message: 'your choice:',default: 'red',choices: [{value: 'red', key: 'R'},{value: 'green', key: 'G'},{value: 'blue', key: 'B'},]},]).then((answers) => {console.log(answers);}).catch((error) => {if (error.isTtyError) {// Prompt couldn't be rendered in the current environment} else {// Something else went wrong}});
    
    • 简写选择功能,除了 Rgb 还有一个 h
    • 输入 h 回车,会得到 help 提示,列出了所有选项
    • 输入 r 回车,会得到 red, 输入 g 回车,会得到 green
效果实例
  • 使用示例6: checkbox 类型演示
    import inquirer from 'inquirer';inquirer.prompt([{type: 'checkbox', // 复选框name: 'choice',message: 'your choice:',default: 0,choices: [{value: 1, name: 'Lily'},{value: 2, name: 'Lucy'},{value: 3, name: 'Lee'},]},]).then((answers) => {console.log(answers);}).catch((error) => {if (error.isTtyError) {// Prompt couldn't be rendered in the current environment} else {// Something else went wrong}});
    
    • 这里提供 a 全选,空格键 选中,i 反选的功能
    • 默认,上下箭来选择
效果实例
  • 使用示例7: password 类型演示
    import inquirer from 'inquirer';inquirer.prompt([{type: 'password', // 密码框name: 'password',message: 'your password:',},]).then((answers) => {console.log(answers);}).catch((error) => {if (error.isTtyError) {// Prompt couldn't be rendered in the current environment} else {// Something else went wrong}});
    
效果实例
  • 使用示例8: editor 类型演示
    import inquirer from 'inquirer';inquirer.prompt([{type: 'editor', // 编辑器name: 'editor',message: 'your editor text:',},]).then((answers) => {console.log(answers);}).catch((error) => {if (error.isTtyError) {// Prompt couldn't be rendered in the current environment} else {// Something else went wrong}});
    
效果实例
  • 上面中间的这个类似 vim 的界面,会在一个缓存文件中,输入完以后,缓存文件被删除掉
  • 我们输入的结果会被保留下来,如上图
  • 这样做的好处是在文本编辑器中输入复杂的内容

readline

  • readline,是 nodejs 当中的一个内置库,主要帮我们去管理数据流的
  • 命令行当中要交互的方式,一定是需要用户提供一些输入的
  • readline 就可以很好的帮我们去一次一次的读取这个输入流
  • 注意,这个输入不仅是指我们输入一些字符,还包含我们键盘上输入的一切,如上,下,空格,回车等
  • 基本使用
    import * as readLine from 'readline';const rl = readLine.createInterface({input: process.stdin,output: process.stdout,
    });rl.question('your name: ', (answer) => {console.log(answer);rl.close(); // 关闭读取流
    })
    
  • readline 主要用途是根据传入的输入流逐行读取信息
  • 回车的时候,会认为这行输入结束,并且把所有输入的内容传递到输出流中进行展示
  • 这是readline的核心用途
  • 如果调试 readline 源码,可知,它内部会强制将函数转换为构造函数
    if (!(this instanceof Interface)) {return new Interface(input, output, completer, terminal);
    }
    
  • 接着是对 StringDecoder的判断和赋值,这个也是node的一个内置库
    if (StringDecoder === undefined) {StringDecoder = require('string_decoder').StringDecoder;
    }
    
  • 再之后,定义了一些列的参数,调用了 EventEmitter
    EventEmitter.call(this)
    
    • 这个用途是使用 this 继承 EventEmitter, this内部就会生成一些列的属性信息,如 _events, _eventsCount
    • 让当前 Interface 实例具备事件驱动的能力,因为nodejs有单线程,非阻塞IO,事件驱动的特性
    • 也就是说事件驱动,在单线程的nodejs中是非常重要的
  • 再接着,定义一些参数, 对 input 进行判断,也就是分析 input 参数
    if (input && input.input) {// ....
    }
    
  • 再往后找,看readline是如何做事件监听的
    this.output = output; // output: WriteStream 系统输出流
    this.input = input; // input: ReadStream 系统输入流// ...emitKeypressEvents(input, this) // 这里就是监听用户在终端中的键盘输入
    
    • 在 emitKeypressEvents 函数内部,会调用一个 emitKeys 的方法
    • 这里是核心, 其原理和源码不在这里进行剖析

这篇关于前端架构: 脚手架命令行交互核心实现之inquirer和readline的应用教程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/756092

相关文章

QT Creator配置Kit的实现示例

《QTCreator配置Kit的实现示例》本文主要介绍了使用Qt5.12.12与VS2022时,因MSVC编译器版本不匹配及WindowsSDK缺失导致配置错误的问题解决,感兴趣的可以了解一下... 目录0、背景:qt5.12.12+vs2022一、症状:二、原因:(可以跳过,直奔后面的解决方法)三、解决方

深入浅出Spring中的@Autowired自动注入的工作原理及实践应用

《深入浅出Spring中的@Autowired自动注入的工作原理及实践应用》在Spring框架的学习旅程中,@Autowired无疑是一个高频出现却又让初学者头疼的注解,它看似简单,却蕴含着Sprin... 目录深入浅出Spring中的@Autowired:自动注入的奥秘什么是依赖注入?@Autowired

MySQL中On duplicate key update的实现示例

《MySQL中Onduplicatekeyupdate的实现示例》ONDUPLICATEKEYUPDATE是一种MySQL的语法,它在插入新数据时,如果遇到唯一键冲突,则会执行更新操作,而不是抛... 目录1/ ON DUPLICATE KEY UPDATE的简介2/ ON DUPLICATE KEY UP

Python中Json和其他类型相互转换的实现示例

《Python中Json和其他类型相互转换的实现示例》本文介绍了在Python中使用json模块实现json数据与dict、object之间的高效转换,包括loads(),load(),dumps()... 项目中经常会用到json格式转为object对象、dict字典格式等。在此做个记录,方便后续用到该方

JWT + 拦截器实现无状态登录系统

《JWT+拦截器实现无状态登录系统》JWT(JSONWebToken)提供了一种无状态的解决方案:用户登录后,服务器返回一个Token,后续请求携带该Token即可完成身份验证,无需服务器存储会话... 目录✅ 引言 一、JWT 是什么? 二、技术选型 三、项目结构 四、核心代码实现4.1 添加依赖(pom

SpringBoot路径映射配置的实现步骤

《SpringBoot路径映射配置的实现步骤》本文介绍了如何在SpringBoot项目中配置路径映射,使得除static目录外的资源可被访问,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一... 目录SpringBoot路径映射补:springboot 配置虚拟路径映射 @RequestMapp

Python与MySQL实现数据库实时同步的详细步骤

《Python与MySQL实现数据库实时同步的详细步骤》在日常开发中,数据同步是一项常见的需求,本篇文章将使用Python和MySQL来实现数据库实时同步,我们将围绕数据变更捕获、数据处理和数据写入这... 目录前言摘要概述:数据同步方案1. 基本思路2. mysql Binlog 简介实现步骤与代码示例1

Redis实现高效内存管理的示例代码

《Redis实现高效内存管理的示例代码》Redis内存管理是其核心功能之一,为了高效地利用内存,Redis采用了多种技术和策略,如优化的数据结构、内存分配策略、内存回收、数据压缩等,下面就来详细的介绍... 目录1. 内存分配策略jemalloc 的使用2. 数据压缩和编码ziplist示例代码3. 优化的

基于C#实现PDF转图片的详细教程

《基于C#实现PDF转图片的详细教程》在数字化办公场景中,PDF文件的可视化处理需求日益增长,本文将围绕Spire.PDFfor.NET这一工具,详解如何通过C#将PDF转换为JPG、PNG等主流图片... 目录引言一、组件部署二、快速入门:PDF 转图片的核心 C# 代码三、分辨率设置 - 清晰度的决定因

Java Kafka消费者实现过程

《JavaKafka消费者实现过程》Kafka消费者通过KafkaConsumer类实现,核心机制包括偏移量管理、消费者组协调、批量拉取消息及多线程处理,手动提交offset确保数据可靠性,自动提交... 目录基础KafkaConsumer类分析关键代码与核心算法2.1 订阅与分区分配2.2 拉取消息2.3