实现一个简单的 node 应用之 todo list2

简介: 实现一个简单的 node 应用之 todo list2

五、inquirer

inquirer 是一个用户与命令行交互工具。github.com/SBoudrias/I…

1. 安装依赖

yarn add inquirer

当展示出所有的任务后,实际上需要上下移动光标,然后执行后续的操作,因此就要借助 inquirer 库来实现这个目标!

2. 操作任务(功能 4)

// index.js
const db = require('./db');
const inquirer = require('inquirer');
// 添加新任务
module.exports.add = async (taskContent) => {
  // 1.读取文件
  const list = await db.read();
  // 2.添加一个任务
  list.push({title: taskContent, completed: false});
  // 3.将任务写入文件
  await db.write(list);
}
// 清空任务列表
module.exports.clear = async () => {
  await db.write([]);
}
// 展示所有事项
module.exports.showAll = async () => {
  // 1. 读出之前的任务
  const list = await db.read();
  // 2. 打印之前的任务
  // list.forEach((task, index) => {
  //   console.log(`${task.completed ? '[x]' : '[_]'} ${index + 1} -> ${task.title}`);
  // });
  // 发起询问
  inquirer
    .prompt({
        type: 'list',
        name: 'index',
        message: '你想要执行哪一项任务?',
        choices: [
          { name: '+ 添加任务', value: '-2'},
          { name: '- 退出', value: '-1'},
          ...list.map((task, index) => {
            return { name: `${task.completed ? '[x]' : '[_]'} ${index + 1} -> ${task.title}`, value: index }
          })
        ],
      })
    .then((answer) => {
      const index = parseInt(answer.index);
      if (index >= 0) {
        // 选中了一个任务
        inquirer.prompt({
          type: 'list',
          name: 'action',
          message: '请选择操作',
          choices: [
            {name: '退出', value: 'quit'},
            {name: '已完成', value: 'completed'},
            {name: '未完成', value: 'incomplete'},
            {name: '改标题', value: 'updateTitle'},
            {name: '删除', value: 'remove'},
          ]
        }).then(answer => {
          console.log(answer.action);
          switch (answer.action) {
            case 'completed':
              list[index].completed = true;
              db.write(list)
              break;
            case 'incomplete':
              list[index].completed = false;
              db.write(list)
              break;
            case 'updateTitle':
              inquirer.prompt({
                type: 'input',
                name: 'title',
                message: '请输入新的标题',
                default: list[index].title // 原标题
              }).then(answer => {
                list[index].title = answer.title;
                db.write(list);
              });
              break;
            case 'remove':
              list.splice(index, 1);
              db.write(list);
              break;
          }
        })
      } else if (index === -2) {
        // 添加任务
        inquirer.prompt({
          type: 'input',
          name: 'title',
          message: '请添加新任务标题',
        }).then(answer => {
          list.push({
            title: answer.title,
            completed: false
          })
          db.write(list);
        })
      }
    });
}


12.jpg


3. 代码优化

// index.js
const db = require('./db');
const inquirer = require('inquirer');
// 1. 添加新任务
module.exports.add = async (taskContent) => {
  // 1.读取文件
  const list = await db.read();
  // 2.添加一个任务
  list.push({title: taskContent, completed: false});
  // 3.将任务写入文件
  await db.write(list);
}
// 2. 清空任务列表
module.exports.clear = async () => {
  await db.write([]);
}
// 3.2.2 添加新任务
function askForAddNewTask (list) {
  inquirer.prompt({
    type: 'input',
    name: 'title',
    message: '请添加新任务标题',
  }).then(answer => {
    list.push({
      title: answer.title,
      completed: false
    })
    db.write(list);
    console.log('添加成功!');
  })
}
// 3.2.1.1 设置已完成状态
async function setCompletedState (list, index) {
  list[index].completed = true;
  await db.write(list);
  console.log('当前任务已完成!');
}
// 3.2.1.2 设置未完成状态
async function setIncompleteState (list, index) {
  list[index].completed = false;
  await db.write(list);
  console.log('当前任务待完成...');
}
// 3.2.1.3 修改标题
function updateTitle (list, index) {
  inquirer.prompt({
    type: 'input',
    name: 'title',
    message: '请输入新的标题',
    default: list[index].title // 原标题
  }).then(answer => {
    list[index].title = answer.title;
    db.write(list);
    console.log('标题更新成功!');
  });
}
// 3.2.1.4 移除任务
async function removeTask (list, index) {
  list.splice(index, 1);
  await db.write(list);
  console.log('删除成功!');
}
// 3.2.1 后续操作
function askForNextAction (list, index) {
  const actions = {
    setCompletedState,
    setIncompleteState,
    updateTitle,
    removeTask
  }
  inquirer.prompt({
    type: 'list',
    name: 'action',
    message: '请选择操作',
    choices: [
      {name: '退出', value: 'quit'},
      {name: '已完成', value: 'setCompletedState'},
      {name: '未完成', value: 'setIncompleteState'},
      {name: '改标题', value: 'updateTitle'},
      {name: '删除', value: 'removeTask'},
    ]
  }).then(answer => {
    const currentAction = actions[answer.action];
    currentAction && currentAction(list, index);
    // switch (answer.action) {
    //   case 'setCompletedState':
    //     setCompletedState(list, index);
    //     break;
    //   case 'setIncompleteState':
    //     setIncompleteState(list, index);
    //     break;
    //   case 'updateTitle':
    //     updateTitle(list, index);
    //     break;
    //   case 'removeTask':
    //     removeTask(list, index);
    //     break;
    // }
  })
}
// 3.2 打印之前的任务 + 后续操作
function displayTasks (list) {
  inquirer
  .prompt({
      type: 'list',
      name: 'index',
      message: '你想要执行哪一项任务?',
      choices: [
        { name: '+ 添加任务', value: '-2'},
        { name: '- 退出', value: '-1'},
        ...list.map((task, index) => {
          return { name: `${task.completed ? '[x]' : '[_]'} ${index + 1} -> ${task.title}`, value: index }
        })
      ],
    })
  .then((answer) => {
    const index = parseInt(answer.index);
    if (index >= 0) {
      // 3.2.1 选中了一个任务,执行后续操作
      askForNextAction(list, index);
    } else if (index === -2) {
      // 3.2.2 添加新任务
      askForAddNewTask(list);
    }
  });
}
// 3. 展示所有事项
module.exports.showAll = async () => {
  // 3.1 读出之前的任务
  const list = await db.read();
  // 3.2 打印之前的任务
  displayTasks(list);
}


六、代码发布

1. 设置 shebang

让用户自动执行 node,参考:zhuanlan.zhihu.com/p/262456371

在 cli.js 中的首行添加一段 shebang 代码:

// cli.js
#!/usr/bin/env node

2. 配置 package.json

{
  "name": "cpc-node-todo-1",
  "bin": {
    "cpc-todo": "./cli.js"
  },
  "files": [
    "cli.js",
    "db.js",
    "index.js"
  ],
  "version": "0.0.3",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "commander": "^8.0.0",
    "inquirer": "^8.1.2"
  }
}
  • name 字段表示,包的名称,以后通过这个名称来下载使用。
  • bin 字段表示,以后用户在终端中可直接运行的命令。


13.jpg


  • files 字段表示,需要打包上传的文件。这里是 cli.js、index.js、db.js 三个文件,当然如果说,你的目录里就只有这三个 js 文件的话,那么该字段就可以直接写成: "files": ["*.js"]

3. 发布到 NPM

  1. 1.npm login (此步骤需要填写用户名和密码,以及邮箱。)
  2. 2.npm publish
  3. 3.npm logout

4. 下载使用

  1. 1.打开终端,全局安装:npm i -g cpc-node-todo-1
  2. 2.安装好后,通过 cpc-todo 来调用这个 node 应用,注意这个 cpc-todo 就是打包之前 package.json 中设置的 bin 字段的内容。


14.jpg


  1. 3.如果不想用了,通过以下命令来卸载即可: npm un -g cpc-todo-1

5. 包的更新

略。


七、单元测试

1. jest

www.jestjs.cn/docs/gettin…

npm install --save-dev jest
目录
相关文章
|
1月前
|
Web App开发 监控 JavaScript
【Node系列】创建第一个服务器应用
Node.js是一个基于Chrome V8引擎的JavaScript运行环境,可以用于构建高性能的网络应用程序。它采用事件驱动、非阻塞I/O模型,使得程序可以以高效地方式处理并发请求。
23 4
|
4天前
|
开发框架 JavaScript 中间件
中间件应用Koa.js(Node.js)
我们添加了两个中间件。第一个中间件记录请求的开始时间,并在下一个中间件执行完毕后计算并打印出请求的总时间。第二个中间件与之前的示例相同,它设置响应体为 "Hello World"
20 6
|
15天前
|
JavaScript 前端开发 持续交付
【专栏】Vue.js和Node.js如何结合构建现代Web应用
【4月更文挑战第27天】本文探讨了Vue.js和Node.js如何结合构建现代Web应用。Vue.js作为轻量级前端框架,以其简洁易懂、组件化开发、双向数据绑定和虚拟DOM等特点受到青睐;而Node.js是高性能后端平台,具备事件驱动、非阻塞I/O、丰富生态系统和跨平台优势。两者结合实现前后端分离,高效通信,并支持热更新、持续集成、跨平台和多端适配,为开发高性能、易维护的Web应用提供强有力的支持。
|
1月前
|
存储 JavaScript 前端开发
Angular 应用 node_modules 子文件夹 @types 的作用介绍
Angular 应用 node_modules 子文件夹 @types 的作用介绍
15 1
|
4天前
|
JavaScript 中间件 API
中间件应用Express.js(Node.js)
我们定义了一个名为 `logger` 的中间件函数。它接受请求对象、响应对象以及下一个中间件函数作为参数。当接收到请求时,它会打印出请求的 HTTP 方法和 URL,然后调用 `next()` 函数来将控制权传递给下一个中间件或路由处理器。我们使用 `app.use()` 方法将 `logger` 中间件添加到了应用级别的中间件堆栈中,这意味着它将对所有请求生效。
12 3
|
6天前
|
数据采集 JavaScript 数据可视化
Node.js爬虫在租房信息监测与分析中的应用
Node.js爬虫在租房信息监测与分析中的应用
|
13天前
|
运维 JavaScript Java
Serverless 应用引擎产品使用之阿里云Serverless函数计算中,在Node.js环境中执行jar文件如何解决
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
21 0
|
2月前
|
Web App开发 JavaScript 前端开发
深入浅出:Node.js 在后端开发中的应用与实践
【2月更文挑战第13天】本文旨在探讨Node.js这一流行的后端技术如何在现代Web开发中被应用以及它背后的核心优势。通过深入分析Node.js的非阻塞I/O模型、事件驱动机制和单线程特性,我们将揭示其在处理高并发场景下的高效性能。同时,结合实际开发案例,本文将展示如何利用Node.js构建高性能、可扩展的后端服务,以及在实际项目中遇到的挑战和解决方案。此外,我们还将讨论Node.js生态系统中的重要工具和库,如Express.js、Koa.js等,它们如何帮助开发者快速搭建和部署应用。通过本文的探讨,读者将获得对Node.js在后端开发中应用的深入理解,以及如何有效利用这一技术来提升开发效率
122 2
|
2月前
|
JavaScript 前端开发
node.js第四天--ajax在项目中的应用
node.js第四天--ajax在项目中的应用
27 0
|
3月前
|
JavaScript NoSQL Redis
深入浅出:使用 Docker 容器化部署 Node.js 应用
在当今快速发展的软件开发领域,Docker 作为一种开源的容器化技术,已经成为了提高应用部署效率、实现环境一致性和便于维护的关键工具。本文将通过一个简单的 Node.js 应用示例,引导读者从零开始学习如何使用 Docker 容器化技术来部署应用。我们不仅会介绍 Docker 的基本概念和操作,还会探讨如何构建高效的 Docker 镜像,并通过 Docker Compose 管理多容器应用。此外,文章还将涉及到一些最佳实践,帮助读者更好地理解和应用 Docker 在日常开发和部署中的强大功能。
151 0