使用 Node.js 构建交互式 CLI 应用程序:初学者教程

119次阅读
没有评论

介绍

命令行界面 (CLI) 是功能强大的工具,允许用户通过基于文本的命令与应用程序交互。虽然乍一看可能有点吓人,但使用 Node.js 构建 CLI 应用程序却出奇地简单,并且对于自动执行任务、收集数据或创建开发者工具非常有用。

在本教程中,我们将构建一个 房地产销售数据收集器——一个交互式 CLI 应用程序,用于收集公寓销售信息并将其保存到 JSON 文件中。这个实际示例将教你一些基本的 CLI 开发概念,并帮助你创建真正有用的应用程序。

您将学到什么

  • 📝 如何创建用户输入的交互式提示
  • ✅ 输入验证技术
  • 💾 文件操作和 JSON 数据管理
  • 🎯 CLI 应用程序中的错误处理
  • 🏗️ 构建可维护的 CLI 代码

先决条件

  • 基本的 JavaScript 知识
  • 您的系统上安装了 Node.js
  • 文本编辑器或 IDE

入门

首先,让我们了解一下我们正在构建什么。我们的 CLI 应用程序将:

  1. 提示用户公寓详细信息(地址、大小、价格等)
  2. 收集卖家和买家信息
  3. 验证所有输入
  4. 显示确认摘要
  5. 将数据保存到 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"
  }
]

关键要点

🎯我们学到了什么:

  1. 交互式输入 :用于readline 创造引人入胜的用户体验
  2. 验证:通过输入验证确保数据质量
  3. 错误处理:优雅地管理错误和边缘情况
  4. 文件操作:读取和写入 JSON 文件
  5. 代码组织:构建 CLI 应用程序以实现可维护性

您可以添加的增强功能

准备好将你的 CLI 提升到一个新的水平了吗?尝试添加:

  • 🎨使用类似库的 颜色和样式chalk
  • 📊长时间操作的 进度条
  • 🔄编辑现有记录 功能
  • 📈数据分析功能(平均价格、统计数据)
  • 🌍国际化 支持
  • ⚙️用于自定义的 配置文件

结论

使用 Node.js 构建 CLI 应用程序既有成就感又实用。您已经学习了如何创建交互式体验、验证用户输入以及如何管理数据持久性。这些技能对于创建开发者工具、自动化脚本或数据收集应用程序非常有价值。

您在这里学到的模式可以应用于无数其他 CLI 应用程序。无论您构建的是部署工具、数据处理器还是交互式问卷,基础都是相同的。

正文完
 0
Pa2sw0rd
版权声明:本站原创文章,由 Pa2sw0rd 于2025-09-03发表,共计5863字。
转载说明:Unless otherwise specified, all articles are published by cc-4.0 protocol. Please indicate the source of reprint.
评论(没有评论)