Javascript 如何使用node js创建交互式控制台界面?
我正在创建一个控制台界面,在这个界面中,程序问一些问题,用户通过控制台回答,有些问题用户只能输入有限数量的输入,我在Javascript 如何使用node js创建交互式控制台界面?,javascript,json,node.js,Javascript,Json,Node.js,我正在创建一个控制台界面,在这个界面中,程序问一些问题,用户通过控制台回答,有些问题用户只能输入有限数量的输入,我在节点js中找到了一些获取控制台输入的方法,但找不到限制用户输入的方法,并且一个接一个地提问,提问后,您希望从中创建一个JSON对象。 例如,我将提出以下问题: 你叫什么名字 列出你的3个爱好 输入所需的用户名 在问了这些问题之后,我将构建一个类似于json的json对象 {"name":"codebean","hobbies":['Exploring','Coding'
节点js中找到了一些获取控制台输入的方法,但找不到限制用户输入的方法,并且一个接一个地提问,提问后,您希望从中创建一个JSON
对象。
例如,我将提出以下问题:
- 你叫什么名字
- 列出你的3个爱好
- 输入所需的用户名李>
在问了这些问题之后,我将构建一个类似于json的json
对象
{"name":"codebean","hobbies":['Exploring','Coding','Trucking'],"username":'codebean'}
我面临的困难有:
- 如何一个接一个地问问题
- 将用户输入限制为特定计数
- 输入最后一个问题的答案后终止程序
我对NodeJs只有很少的经验,我能建立的只是垃圾,以下是我建立的
process.stdin.setEncoding('utf8');
var输入=[];
process.stdin.on('readable',function(){
log(“你叫什么名字”);
var name=process.stdin.read();
如果((名称!==null)&&(名称!='/n')){
input.push(name.split('/n')[0]);
控制台日志(输入);
}
console.log('列出你的3个爱好?');
var=process.stdin.read();
});
process.stdin.on('end',function()){
控制台日志(输入);
});代码>在NodeJS中创建了CLI应用程序之后,我建议使用类似库的方法来更好地组织代码。在我看来,一个图书馆会让它比你天真地做的事情更具可读性
但是,如果您想要一些本机的替代方案,您可以使用节点使事情看起来更有条理,而不是在stdin回调中处理它:
var EventEmitter = require('events');
var prompt = new EventEmitter();
var current = null;
var result = {};
process.stdin.resume();
process.stdin.on('data', function(data){
prompt.emit(current, data.toString().trim());
});
prompt.on(':new', function(name, question){
current = name;
console.log(question);
process.stdout.write('> ');
});
prompt.on(':end', function(){
console.log('\n', result);
process.stdin.pause();
});
prompt.emit(':new', 'name', 'What is your name?');
prompt.on('name', function(data){
result.name = data;
prompt.emit(':new', 'hobbies', 'What are your hobbies?');
});
prompt.on('hobbies', function(data){
result.hobbies = data.split(/,\s?/);
prompt.emit(':new', 'username', 'What is your username?');
});
prompt.on('username', function(data){
result.username = data;
prompt.emit(':end');
});
这段代码使用某种状态跟踪方法(我不知道是否有实际的术语)
基本上,有一个变量跟踪您的编程正在寻找的内容,在我们的例子中是current
。此变量还用于在收到数据时触发我们的提示符
EventEmitter
在事件内部,我们可以更改当前
变量以请求其他内容(我制作了一个速记:new
事件来执行此操作),随意操作数据,还可以将其添加到结果
变量中
如果您想“标记”您的输入(开头有一个小标记),只需使用stdin即可。write
:
prompt.on(':new', function(){
// ...
process.stdin.write('> ');
});
下面是该代码在运行时的样子:
$node。。。
你的名字叫什么?
>杰门·马佐尼
你的爱好是什么?
>编程、哲学、抚摸猫
你的用户名是什么?
>杰门
{姓名:'Jamen Marzonie',
爱好:[“编程”、“哲学”、“抚摸猫”],
用户名:'jamen'}
我经常在这个案例中使用协同程序,它产生问题并使用答案。Co例程是使用值生成下一个结果的生成器。在我们的例子中,它们使用用户的响应,并产生提示
这使得提示序列和简单的状态管理具有极高的可读性和可调试性
注意在节点14中运行的示例代码中使用了函数*
。该语法在javascript中定义了一个协同程序
示例代码末尾的前两个“库”函数公开了节点的本机stdio功能,这样您就可以编写“有状态”协程,例如
function* createSimpleSequence(print) {
print("Welcome to the game");
let playerName = "";
while(!playerName){
playerName = yield "What is your name? ";
}
print(`Hello, ${playerName}`);
yield "Press enter to restart the game";
}
请注意,没有明确的状态管理,因为协同例程允许我们在产生问题后“从哪里开始”,我们可以使用while循环和其他明显同步的控制流原语来决定如何以及何时在状态之间“前进”
原始海报要求的完整示例如下所示
function* createOriginalPostersSequence(print) {
let name = "";
while (!name) {
name = yield "What is your name?";
if (!name) {
print("Your name cannot be empty");
}
}
let hobbyString = "";
while (!hobbyString) {
hobbyString = yield "List three of your hobbies, separated by ','";
const hobbyCount = hobbyString.split(",").length;
if (hobbyCount !== 3) {
if (hobbyCount === 0) {
print("Your hobbies cannot be empty");
} else if (hobbyCount == 1) {
print("What! Do you really only have one hobby, think again!");
} else if (hobbyCount == 2) {
print("Two is better than one, but I asked for three!");
}
hobbyString = "";
}
}
const hobbies = hobbyString.split(",").map((hobby) => hobby.trim());
let username = "";
while (!username) {
username = yield "What is your username?";
if (!username) {
print("Your username cannot be empty!");
}
if (!username.match(/[a-z_]+/)) {
print(
"Your username can only contain lowercase letters and underscores."
);
username = "";
}
}
const data = {
name,
hobbies,
username,
};
print(`Your full data is ${JSON.stringify(data)}`);
}
最后,这是完整的源代码,它将运行简单序列,然后在节点14中以交互方式运行原始海报请求的交互式提示序列
// core 'library' exposing native node console capabilities for co-routines
function getAnswer() {
process.stdin.resume();
return new Promise((resolve) => {
process.stdin.once("data", function (data) {
resolve(data.toString().trim());
});
});
}
async function runSequence(sequenceFactory, clearScreen = true) {
function print(msg, end = "\n") {
process.stdin.write(msg + end);
}
let answer = undefined;
const sequence = sequenceFactory(print);
while (true) {
const { value: question } = sequence.next(answer);
if (question) {
print(question, " : ");
answer = await getAnswer();
if (clearScreen) {
console.clear();
}
} else {
break;
}
}
}
// examples using the library
function* createSimpleSequence(print) {
print("Welcome to the game");
let playerName = "";
while (!playerName) {
playerName = yield "What is your name? ";
}
print(`Hello, ${playerName}`);
yield "Press enter to restart the game";
}
function* createOriginalPostersSequence(print) {
let name = "";
while (!name) {
name = yield "What is your name?";
if (!name) {
print("Your name cannot be empty");
}
}
let hobbyString = "";
while (!hobbyString) {
hobbyString = yield "List three of your hobbies, separated by ','";
const hobbyCount = hobbyString.split(",").length;
if (hobbyCount !== 3) {
if (hobbyCount === 0) {
print("Your hobbies cannot be empty");
} else if (hobbyCount == 1) {
print("What! Do you really only have one hobby, think again!");
} else if (hobbyCount == 2) {
print("Two is better than one, but I asked for three!");
}
hobbyString = "";
}
}
const hobbies = hobbyString.split(",").map((hobby) => hobby.trim());
let username = "";
while (!username) {
username = yield "What is your username?";
if (!username) {
print("Your username cannot be empty!");
}
if (!username.match(/[a-z_]+/)) {
print(
"Your username can only contain lowercase letters and underscores."
);
username = "";
}
}
const data = {
name,
hobbies,
username,
};
print(`Your full data is ${JSON.stringify(data)}`);
}
// demo to run examples
async function run() {
await runSequence(createSimpleSequence);
await runSequence(createOriginalPostersSequence);
process.exit(0);
}
run();
就个人而言,在NodeJS中创建了cli和其他东西之后,我会使用一个库来完成这类事情。使用stdio streams在使用提示时有点混乱。你可以搜索你喜欢的,但是像这样的流行提示可能会做。提示看起来不错,但我想用原生方式来做?有什么帮助吗?对于一个更华丽的基于文本的界面,你可以看看。祝福似乎很好,谢谢你的帮助info@CodeBean,希望这有帮助。请记住,单击绿色复选标记可以接受答案。如果你需要的话,请随时问我问题。谢谢你的时间,这真的很有帮助!