欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺析node命令行交互原理

 更新時(shí)間:2023年05月24日 09:31:13   作者:PHM  
當(dāng)我們使用腳手架去創(chuàng)建一個項(xiàng)目的時(shí)候,通常會通過命令行交互來獲取一些信息,比如填項(xiàng)目名稱,選擇項(xiàng)目模板,選擇版本,我們雖然經(jīng)常用到,但是想必對于其中的原理還是不太了解,本文將待大家詳細(xì)介紹一下node命令行的交互原理,需要的朋友可以參考下

什么是命令行交互

當(dāng)我們使用腳手架去創(chuàng)建一個項(xiàng)目的時(shí)候,通常會通過命令行交互來獲取一些信息:比如填項(xiàng)目名稱;選擇項(xiàng)目模板;選擇版本;需要安裝哪些額外的工具等等。這些我們雖然經(jīng)常用到,但是想必對于其中的原理還是不太了解。

常用的命令行交互庫

在開發(fā)腳手架項(xiàng)目時(shí),如果需要命令行交互去獲取一些信息,最常用的庫是inquirer,其使用也非常簡單:下面給出簡單的示例:

var inquirer = require('inquirer');
inquirer.prompt([
  {
    type: 'list',
    name: 'projectType',
    message: '請選擇初始化類型',
    default: TYPE_PROJECT,
    choices: [
      {
        name: '項(xiàng)目',
        value: TYPE_PROJECT,
      },
      {
        name: '組件',
        value: TYPE_COMPONENT,
      },
    ],
  },
]);
// 詢問項(xiàng)目的基本信息
inquirer.prompt([
  {
    type: 'input',
    name: 'projectName',
    message: '請確認(rèn)項(xiàng)目名稱',
    default: this.projectName,
    validate: function(v) {
      const done = this.async();
      setTimeout(function() {
        // 校驗(yàn)規(guī)則:
        // 1. 首字母必須為英文字符
        // 2. 尾字母必須為英文或數(shù)字,不能為字符
        // 3. 字符僅允許"-_"
        // 4. 長度必須大于等于1
        if (!/^[a-zA-Z][\w-]{0,}[a-zA-Z0-9]$/.test(v)) {
          // Pass the return value in the done callback
          done('請輸入合法的項(xiàng)目名稱');
          return;
        }
        // Pass the return value in the done callback
        done(null, true);
      }, 0);
    }
  },
  {
    type: 'input',
    name: 'projectVersion',
    message: '請輸入項(xiàng)目版本號',
    default: '1.0.0',
    validate: function(v) {
      const done = this.async();
      setTimeout(() => {
        if (!semver.valid(v)) {
          done('請輸入合法的版本號');
          return;
        }
        done(null, true);
      }, 0)
    },
    filter: function(v) {
      if (!!semver.valid(v)) {
        return semver.valid(v)
      } else {
        return v
      }
    }
  }
])

開發(fā)命令行工具常用庫或API

readline

readline是node提供的原生API,它可以幫助我們實(shí)現(xiàn)命令行交互,如下是一個簡單的案例:

const readline = require('node:readline');
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});
rl.question('What do you think of Node.js? ', (answer) => {
  // TODO: Log the answer in a database
  console.log(`Thank you for your valuable feedback: ${answer}`);
  rl.close();
});

運(yùn)行這個代碼就會出現(xiàn)命令行輸入的效果,輸入完成回車會在回調(diào)里拿到輸入的內(nèi)容,調(diào)用rl.close()會結(jié)束交互。

ansi-escapes

ANSI轉(zhuǎn)義序列是用于在視頻文本終端和終端模擬器上控制光標(biāo)位置、顏色、字體樣式和其他選項(xiàng)的帶內(nèi)信令的標(biāo)準(zhǔn)。某些字節(jié)序列(大多數(shù)以ASCII轉(zhuǎn)義字符和方括號字符開始)嵌入到文本中。終端將這些序列解釋為命令,而不是逐字顯示的文本。
當(dāng)我們想改變命令行的文字樣式、位置等就可以使用這個標(biāo)準(zhǔn),比如我想打印紅色的文字,那么我會這樣寫:

console.log('\x1B[31m%s\x1B[0m', 'I am red');

\x1B[是固定寫法,31表示紅色字體背景,m表示設(shè)置代碼后面字符的顏色和樣式,%s是log方法第二個參數(shù)的占位符,0m表示打印完后還原正常樣式。執(zhí)行的效果如下

除了顏色當(dāng)然還可以設(shè)置其他樣式,例如下劃線等,替換code即可,具體可以參考:ANSI escape code - HandWiki 里的code表。

// 打印紅色文字
console.log('\x1B[31m%s\x1B[0m', 'I am red');
// 打印文字添加下劃線
console.log('\x1B[4m%s\x1B[0m', 'underline');
// 紅色文字下劃線
console.log('\x1B[31m\x1B[4m%s\x1B[0m', 'I am red and underline');

除了樣式還可以處理光標(biāo)位置,比如想打印完一行后隔兩行再繼續(xù)打印,則可以這樣寫:

// 紅色文字下劃線
console.log('\x1B[31m\x1B[4m%s\x1B[0m', 'I am red and underline');
// cursor 移動
console.log('\x1B[2B%s\x1B[0m', 'I am red and underline');

將m換成B,B前面的數(shù)字表示要空幾行,效果如下:

還有更多的可能你想要的效果,可以查看 ANSI escape code - HandWiki

rxjs

RxJS 是一個用于處理異步編程的 JavaScript 庫,目標(biāo)是使編寫異步和基于回調(diào)的代碼更容易。

自己開發(fā)一個命令行列表選擇功能

流程圖

代碼實(shí)現(xiàn)

首先模仿inquirer的使用方式搭一個簡單的架子:

const option = {
  type: 'list',
  name: 'name',
  message: 'select a name',
  choices: [
    { name: 'sam', value: 'sam' },
    { name: 'tom', value: 'tom' },
    { name: 'jerry', value: 'jerry' }
  ]
}
function prompt(option) {
  return new Promise((resolve, reject) => {})
}
prompt(option).then((answer) => {
  console.log(answer)
})

然后實(shí)現(xiàn)一個List類,由它來做具體的實(shí)現(xiàn):

const { EventEmitter } = require('events');
const rl = require('readline');
const MuteStream = require('mute-stream');
const { fromEvent } = require('rxjs');
const ansi = require('ansi-escapes');
class List extends EventEmitter {
  constructor(option) {
    super();
    this.name = option.name;
    this.message = option.message;
    this.choices = option.choices;
    this.input = process.stdin;
    // 通過mute-stream來實(shí)現(xiàn)控制臺的輸入輸出
    const ms = new MuteStream();
    ms.pipe(process.stdout);
    this.output = ms;
    // 創(chuàng)建readline接口
    this.rl = rl.createInterface({
      input: this.input,
      output: this.output,
    });
    // 默認(rèn)選中
    this.selected = option.default || 0;
    this.height = this.choices.length + 1;
    // 監(jiān)聽keypress事件
    this.keypress = fromEvent(this.rl.input, 'keypress').subscribe(
      this.onKeypress
    );
    // 是否選擇完畢
    this.done = false;
  }
  // 鍵盤事件
  onKeypress = (keyMap) => {
    // 獲取key
    const key = keyMap[1];
    if (key.name === 'up') { // 上鍵點(diǎn)擊
      if (this.selected > 0) {
        this.selected--;
      }
    } else if (key.name === 'down') { // 下鍵點(diǎn)擊
      if (this.selected < this.choices.length - 1) {
        this.selected++;
      }
    } else if (key.name === 'return') { // 回車點(diǎn)擊
      this.done = true;
    }
    this.render();
    // 完成選擇后退出
    if (this.done) {
      this.close()
      this.emit('exit', this.choices[this.selected])
    }
  }
  render() {
    // 解除mute狀態(tài)
    this.output.unmute();
    // 清除控制臺
    this.clean();
    // 寫入list內(nèi)容
    this.output.write(this.getContent());
    // 開啟mute狀態(tài) 限制用戶不可輸入
    this.output.mute();
  }
  getContent() {
    if (this.done) {
      return `\x1B[1m${this.message} \x1B[22m\x1B[36m${this.choices[this.selected].name}\x1B[39m\n`;
    } else {
      const title = `\x1B[32m?\x1B[39m \x1B[1m${this.message}(use arrow keys)\x1B[22m\n`;
      const list = this.choices.map((item, index) => {
        // 選中的選項(xiàng)前面加上?
        if (index === this.selected) {
          return `\x1B[36m? ${item.name}\x1B[39m`;
        }
        return `  ${item.name}`;
      });
      return title + list.join('\n');
    }
  }
  // 清除控制臺
  clean() {
    const emptyLines = ansi.eraseLines(this.height);
    this.output.write(emptyLines);
  }
  close() {
    this.output.unmute();
    this.rl.output.end();
    this.rl.pause();
    this.rl.close();
    this.keypress.unsubscribe();
  }
}

然后使用List

function prompt(option) {
  return new Promise((resolve, reject) => {
    try {
      const list = new List(option);
      // 渲染列表
      list.render();
      list.on('exit', (answer) => {
        resolve(answer);
      });
    } catch (error) {
      reject(error);
    }
  });
}
prompt(option).then((answer) => {
  console.log('answer', answer);
});

運(yùn)行效果就是這樣:

到此這篇關(guān)于淺析node命令行交互原理的文章就介紹到這了,更多相關(guān)node 命令行交互內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Node.js、Socket.IO和GPT-4構(gòu)建AI聊天機(jī)器人的項(xiàng)目實(shí)踐

    Node.js、Socket.IO和GPT-4構(gòu)建AI聊天機(jī)器人的項(xiàng)目實(shí)踐

    本文主要介紹了Node.js、Socket.IO和GPT-4構(gòu)建AI聊天機(jī)器人的項(xiàng)目實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • node.js中實(shí)現(xiàn)GET和POST請求的代碼示例

    node.js中實(shí)現(xiàn)GET和POST請求的代碼示例

    在很多場景中,我們的服務(wù)器都需要跟用戶的瀏覽器打交道,如發(fā)送驗(yàn)證碼、登錄表單提交,請求服務(wù)器數(shù)據(jù)一般都使用GET請求,表單提交到服務(wù)器一般都使用POST請求,本文詳細(xì)介紹了在Node.js中如何處理GET和POST請求,需要的朋友可以參考下
    2024-12-12
  • webpack打包、編譯、熱更新Node內(nèi)存不足問題解決

    webpack打包、編譯、熱更新Node內(nèi)存不足問題解決

    Webpack是現(xiàn)在主流的功能強(qiáng)大的模塊化打包工具,在使用Webpack時(shí),如果不注意性能優(yōu)化,有非常大的可能會產(chǎn)生性能問題,下面這篇文章主要給大家介紹了關(guān)于webpack打包、編譯、熱更新Node內(nèi)存不足問題解決的相關(guān)資料,需要的朋友可以參考下
    2023-03-03
  • node版本與node-sass版本不兼容時(shí)的問題及解決

    node版本與node-sass版本不兼容時(shí)的問題及解決

    這篇文章主要介紹了node版本與node-sass版本不兼容時(shí)的問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • 前端常見面試題之a(chǎn)sync/await和promise的區(qū)別

    前端常見面試題之a(chǎn)sync/await和promise的區(qū)別

    async/await是異步代碼的新方式,以前的方法有回調(diào)函數(shù)和Promise,下面這篇文章主要給大家介紹了關(guān)于前端常見面試題之a(chǎn)sync/await和promise區(qū)別的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-07-07
  • node.js中的console.dir方法使用說明

    node.js中的console.dir方法使用說明

    這篇文章主要介紹了node.js中的console.dir方法使用說明,本文介紹了console.dir的方法說明、語法、接收參數(shù)、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下
    2014-12-12
  • 測試驅(qū)動ChatGPT編程示例詳解

    測試驅(qū)動ChatGPT編程示例詳解

    這篇文章主要為大家介紹了測試驅(qū)動ChatGPT編程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • 使用express+multer實(shí)現(xiàn)node中的圖片上傳功能

    使用express+multer實(shí)現(xiàn)node中的圖片上傳功能

    這篇文章主要介紹了使用express+multer實(shí)現(xiàn)node中的圖片上傳功能,需要的朋友可以參考下
    2018-02-02
  • NodeJS自定義模塊寫法(詳解)

    NodeJS自定義模塊寫法(詳解)

    下面小編就為大家?guī)硪黄狽odeJS自定義模塊寫法(詳解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • 零基礎(chǔ)搭建Node.js、Express、Ejs、Mongodb服務(wù)器及應(yīng)用開發(fā)入門

    零基礎(chǔ)搭建Node.js、Express、Ejs、Mongodb服務(wù)器及應(yīng)用開發(fā)入門

    這篇文章主要介紹了零基礎(chǔ)搭建Node.js、Express、Ejs、Mongodb服務(wù)器及應(yīng)用開發(fā)入門,本文在windows8系統(tǒng)下完成本教程,其它系統(tǒng)也可參考,需要的朋友可以參考下
    2014-12-12

最新評論