介绍
命令行界面 (CLI) 是功能强大的工具,允许用户通过基于文本的命令与应用程序交互。虽然乍一看可能有点吓人,但使用 Node.js 构建 CLI 应用程序却出奇地简单,并且对于自动执行任务、收集数据或创建开发者工具非常有用。
在本教程中,我们将构建一个 房地产销售数据收集器——一个交互式 CLI 应用程序,用于收集公寓销售信息并将其保存到 JSON 文件中。这个实际示例将教你一些基本的 CLI 开发概念,并帮助你创建真正有用的应用程序。
您将学到什么
- 📝 如何创建用户输入的交互式提示
- ✅ 输入验证技术
- 💾 文件操作和 JSON 数据管理
- 🎯 CLI 应用程序中的错误处理
- 🏗️ 构建可维护的 CLI 代码
先决条件
- 基本的 JavaScript 知识
- 您的系统上安装了 Node.js
- 文本编辑器或 IDE
入门
首先,让我们了解一下我们正在构建什么。我们的 CLI 应用程序将:
- 提示用户公寓详细信息(地址、大小、价格等)
- 收集卖家和买家信息
- 验证所有输入
- 显示确认摘要
- 将数据保存到 JSON 文件
让我们开始吧!🚀
设置项目
创建一个新目录并初始化您的项目:
mkdir real-estate-cli
cd real-estate-cli
npm init -y
创建一个名为的文件apartment-sales.js
– 这将是我们的主要应用程序文件。
核心概念
1. 使用 readline 进行交互式输入
Node.js 提供了 readline
处理用户输入的模块。设置方法如下:
const readline = require('readline');
// Create an interface for reading user input
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
2. 创建承诺问题
为了使我们的代码更简洁并且更易于与 async/await 配合使用,我们将 readline 包装在 Promise 中:
function askQuestion(question) {return new Promise((resolve) => {rl.question(question, (answer) => {resolve(answer.trim());
});
});
}
这个函数可以让我们在提问的时候使用await
,让我们的代码更加易读!
构建应用程序
让我们一步一步构建我们的应用程序:
步骤 1:输入验证函数
优秀的 CLI 应用程序会验证用户输入。让我们创建一些辅助函数:
// Validate numbers (prices, areas, etc.)
function validateNumber(value, fieldName) {const number = parseFloat(value);
if (isNaN(number) || number <= 0) {throw new Error(`${fieldName} must be a valid positive number`);
}
return number;
}
// Validate email addresses
function validateEmail(email) {const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!regex.test(email)) {throw new Error('Invalid email format');
}
return email;
}
// Validate phone numbers
function validatePhone(phone) {const regex = /^[\d\s\-\+\(\)]{10,}$/;
if (!regex.test(phone)) {throw new Error('Invalid phone format (minimum 10 digits)');
}
return phone;
}
步骤 2:数据收集功能
现在让我们创建收集所有公寓销售数据的主要功能:
async function collectApartmentSaleData() {console.log('=== APARTMENT SALE DATA COLLECTOR ===\n');
try {const saleData = {};
// Apartment Information
console.log('--- Apartment Details ---');
saleData.apartment = {address: await askQuestion('Full address:'),
city: await askQuestion('City:'),
postalCode: await askQuestion('Postal code:'),
area: validateNumber(await askQuestion('Area (m²):'), 'Area'),
rooms: parseInt(await askQuestion('Number of rooms:')),
bedrooms: parseInt(await askQuestion('Number of bedrooms:')),
floor: await askQuestion('Floor:'),
elevator: (await askQuestion('Elevator (yes/no):')).toLowerCase() === 'yes',
balcony: (await askQuestion('Balcony (yes/no):')).toLowerCase() === 'yes',
parking: (await askQuestion('Parking (yes/no):')).toLowerCase() === 'yes'};
// Sale Information
console.log('\n--- Sale Details ---');
saleData.sale = {price: validateNumber(await askQuestion('Sale price (€):'), 'Price'),
saleDate: await askQuestion('Sale date (DD/MM/YYYY):'),
saleType: await askQuestion('Sale type (direct/agency):'),
commission: parseFloat(await askQuestion('Commission (%):') || '0')
};
// Seller Information
console.log('\n--- Seller Information ---');
saleData.seller = {firstName: await askQuestion('First name:'),
lastName: await askQuestion('Last name:'),
email: validateEmail(await askQuestion('Email:')),
phone: validatePhone(await askQuestion('Phone:')),
address: await askQuestion('Address:')
};
// Buyer Information
console.log('\n--- Buyer Information ---');
saleData.buyer = {firstName: await askQuestion('First name:'),
lastName: await askQuestion('Last name:'),
email: validateEmail(await askQuestion('Email:')),
phone: validatePhone(await askQuestion('Phone:')),
address: await askQuestion('Address:')
};
// Add metadata
saleData.createdAt = new Date().toISOString();
saleData.id = Date.now().toString();
return saleData;
} catch (error) {console.error(`Input error: ${error.message}`);
return null;
}
}
步骤 3:JSON 文件管理
让我们创建函数将数据保存到 JSON 文件:
const fs = require('fs');
function saveToJSON(data, filename = 'apartment-sales.json') {
try {let existingSales = [];
// Check if file already exists
if (fs.existsSync(filename)) {const content = fs.readFileSync(filename, 'utf8');
existingSales = JSON.parse(content);
}
// Add new sale
existingSales.push(data);
// Save file
fs.writeFileSync(filename, JSON.stringify(existingSales, null, 2), 'utf8');
console.log(`\n✅ Sale saved successfully to ${filename}`);
console.log(`📊 Total sales: ${existingSales.length}`);
return true;
} catch (error) {console.error(`❌ Save error: ${error.message}`);
return false;
}
}
步骤 4:摘要显示
在保存之前,让我们向用户显示一个摘要:
function displaySummary(saleData) {console.log('\n=== SALE SUMMARY ===');
console.log(`🏠 Apartment: ${saleData.apartment.area}m² in ${saleData.apartment.city}`);
console.log(`💰 Price: €${saleData.sale.price.toLocaleString()}`);
console.log(`👤 Seller: ${saleData.seller.firstName} ${saleData.seller.lastName}`);
console.log(`👤 Buyer: ${saleData.buyer.firstName} ${saleData.buyer.lastName}`);
console.log(`📅 Sale date: ${saleData.sale.saleDate}`);
}
步骤 5:主要应用程序逻辑
最后,让我们把所有内容放在一起:
async function main() {
try {const saleData = await collectApartmentSaleData();
if (saleData) {displaySummary(saleData);
const confirm = await askQuestion('\nSave this data? (yes/no):');
if (confirm.toLowerCase() === 'yes') {saveToJSON(saleData);
} else {console.log('❌ Save cancelled');
}
}
} catch (error) {console.error(`Application error: ${error.message}`);
} finally {rl.close();
}
}
// Run the application
if (require.main === module) {main();
}
运行您的应用程序
要运行 CLI 应用程序:
node apartment-sales.js
该应用程序将指导您完成每个步骤,验证您的输入,显示摘要,并将数据保存到 JSON 文件。
JSON 输出示例
您保存的数据将如下所示:
[
{
"apartment": {
"address": "123 Main Street",
"city": "Paris",
"postalCode": "75001",
"area": 85,
"rooms": 4,
"bedrooms": 2,
"floor": "3rd",
"elevator": true,
"balcony": true,
"parking": false
},
"sale": {
"price": 450000,
"saleDate": "15/03/2024",
"saleType": "agency",
"commission": 3.5
},
"seller": {
"firstName": "John",
"lastName": "Doe",
"email": "[email protected]",
"phone": "+33123456789",
"address": "456 Oak Avenue"
},
"buyer": {
"firstName": "Jane",
"lastName": "Smith",
"email": "[email protected]",
"phone": "+33987654321",
"address": "789 Pine Street"
},
"createdAt": "2024-03-15T10:30:00.000Z",
"id": "1710498600000"
}
]
关键要点
🎯我们学到了什么:
- 交互式输入 :用于
readline
创造引人入胜的用户体验 - 验证:通过输入验证确保数据质量
- 错误处理:优雅地管理错误和边缘情况
- 文件操作:读取和写入 JSON 文件
- 代码组织:构建 CLI 应用程序以实现可维护性
您可以添加的增强功能
准备好将你的 CLI 提升到一个新的水平了吗?尝试添加:
- 🎨使用类似库的 颜色和样式
chalk
- 📊长时间操作的 进度条
- 🔄编辑现有记录 功能
- 📈数据分析功能(平均价格、统计数据)
- 🌍国际化 支持
- ⚙️用于自定义的 配置文件
结论
使用 Node.js 构建 CLI 应用程序既有成就感又实用。您已经学习了如何创建交互式体验、验证用户输入以及如何管理数据持久性。这些技能对于创建开发者工具、自动化脚本或数据收集应用程序非常有价值。
您在这里学到的模式可以应用于无数其他 CLI 应用程序。无论您构建的是部署工具、数据处理器还是交互式问卷,基础都是相同的。