Node.js留言板(超详细注释)

news2024/12/24 21:36:19

目录结构如下

app.js

// 一.引入模块
var http = require('http');// 用于创建 HTTP 服务器和处理 HTTP 请求
var fs = require('fs');// 用于读取和写入文件
var url = require('url');// 用于解析URL

// 创建留言数据对象
var msgs = [
    { name: '牛二', content: "我是妞儿", create_at: '2024-1-04 06:12' },
    { name: '张三', content: "我是张三", create_at: '2024-1-22 09:32' },
    { name: '里斯', content: "我是里斯", create_at: '2024-2-23 12:28' },
    { name: '王五', content: "我是王五", create_at: '2024-4-14 17:11' }
];

// 二.创建 HTTP 服务器实例
var server = http.createServer();

// 三.监听用户请求
server.on('request', function (req, res) {
    // 获取当前请求地址
    var currentUrl = req.url;
    //判断页面
    if (currentUrl == '/') {// 首页(fs模块)
        fs.readFile('./views/index.html', 'utf8', function (err, data) {
            if (err) {
                console.log(err);
                return;
            }
            // res.end(data);// data 是首页所有的 html 代码

            // 1.将上面的变量数据组装到html
            var html = '';
            msgs.forEach(function (item, index) {
                html += `
        <li class="list-group-item" style="display: flex; justify-content: space-between; align-items: center;">
            ${item.name}: ${item.content}
            <span >${item.create_at}</span>
            <button class="btn btn-danger btn-sm" onclick="deleteMessage(${index})">删除</button>
        </li>`;
            });

            // console.log(html);

            // 2.重点!!替换 data 的占位符
            var htmlData = data.replace('^_^', html);

            // 3.响应替换后的数据
            res.end(htmlData);// 结束响应,并向客户端发送最终的响应内容
        })

    } else if (currentUrl == '/add') {// 添加页
        fs.readFile('./views/add.html', 'utf8', function (err, data) {
            if (err) {
                console.log(err);
                return;
            }
            res.end(data);
        })

    } else if (currentUrl.indexOf('/doadd') === 0) {
        // get 提交 /doadd?name=xxx&content=xxx req.url 请求路径需用url模块

        var parsedUrl = new URL(req.url, 'http://localhost:8080');
        // 创建新的 URL 对象,解析 req.url 来获取客户端请求的 URL,如 /add
        // 'ht...80' 是基础 URL,用于解析相对 URL,从而得到完整的 URL 地址
        var paramsObj = parsedUrl.searchParams;// 从解析后的 URL 对象中获取查询参数

        // 格式化日期时间
        var date = new Date();
        var hours = date.getHours();
        var minutes = date.getMinutes();
        var hoursStr = (hours < 10 ? '0' : '') + hours;
        var minutesStr = (minutes < 10 ? '0' : '') + minutes;
        var dateStr = date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate() + ' ' + hoursStr + ':' + minutesStr;

        var msg = {
            name: paramsObj.get('name'),
            content: paramsObj.get('content'),
            create_at: dateStr
        };

        // 理论上是给数据库添加一条数据,现在是向数组中压入一条数据
        msgs.push(msg); // 添加留言对象到留言数组中

        // 插入成功,重定向到首页
        res.statusCode = 302; // 声明重定向
        res.setHeader('location', '/'); //设置响应头,指定重定向到网站的根目录
        res.end() // 结束响应,并将其发送给客户端

    } else if (currentUrl.startsWith('/delete')) { // 当前请求的 URL 以 '/delete' 开头
        // 解析并删除对应索引
        var index = parseInt(currentUrl.split('/').pop());
        msgs.splice(index, 1);
        // 删除成功,重定向到首页
        res.statusCode = 302;
        res.setHeader('location', '/');
        res.end();
    }
    else {// 404
        fs.readFile('./views/404.html', 'utf8', function (err, data) {
            if (err) {
                console.log(err);
                return;
            }
            res.end(data);
        })
    }
})

// 四.启动服务
server.listen(8080, function () {
    console.log('启动成功,访问:http://localhost:8080')
})

// 注意
// 终端需要cd转到当前message目录下,再node app.js

// currentUrl.indexOf('/doadd') === 0
// 通过 indexOf() 方法检查当前请求的 URL 是否以 /doadd 开头
// 如果返回 0,则表示当前 URL 的开头与 /doadd 完全匹配
// 如果匹配成功,条件语句将返回 true,否则返回 false

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>留言板</title>
    
    <!-- 引入 Bootstrap 样式表 -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
</head>

<body>
    <!-- 头部容器 -->
    <div class="header container">
        <!-- 页面标题栏 -->
        <div class="page-header">
            <h1>留言板</h1>
            <a class="btn btn-success" href="/add">发表留言</a>
            <!-- 创建按钮链接到“/add”页,设置 Bootstrap 中的成功按钮 -->
        </div>
    </div>

    <!-- 留言容器 -->
    <div class="comments container">
        <ul class="list-group">
            ^_^<!-- 占位符,表示在这里显示留言列表 -->
        </ul>
    </div>

    <script>
        function deleteMessage(index) {
            if (confirm("确定要删除这条留言吗?")) {
                fetch(`/delete/${index}`, { method: 'DELETE' })
                    .then(response => {
                        if (response.ok) {
                            window.location.reload(); // 删除成功后刷新页面
                        } else {
                            console.error('删除留言失败');
                        }
                    })
                    .catch(error => {
                        console.error('删除留言失败', error);
                    });
            }
        }
        // 接受一个要删除的留言的索引参数 `index`
        // 函数首先弹出确认对话框,询问用户是否确定要删除该留言。
        // 如果确认,则通过 `fetch` 函数向服务器发送一个 DELETE 请求,
        // 该请求的路径包含了要删除的留言的索引。
        // 删除成功(即响应状态码为 200 OK),则刷新页面,以展示更新后的留言列表;
        // 删除失败,在控制台输出错误信息。
    </script>


</body>

</html>

add.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>发表留言</title>

    <!-- 将 Bootstrap 的 CSS 文件引入到 HTML 页面中 -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">

</head>

<body>
    <!-- 头部容器 -->
    <div class="header container">
        <!-- 页面标题栏 -->
        <div class="page-header">
            <h1><a href="/">首页</a> <small>发表留言</small></h1>
        </div>
    </div>

    <!-- 评论容器 -->
    <div class="comments container">
        <!-- 创建表单,GET 提交到“/doadd”页 -->
        <form action="/doadd" method="get">

            <div class="form-group">
                <label for="input_name">昵称</label>
                 <!-- 昵称输入框,设置类型为“name”,输入内容的最小和最大长度 -->
                <input type="name" class="form-control" id="input_name" placeholder="请输入姓名" minlength="2" maxlength="10"
                    name="name">
            </div>

            <div class="form-group">
                <label for="input_message">留言内容</label>
                <!-- 留言内容输入框,设置宽度30,高度10,必填,输入内容的最小和最大长度 -->
                <textarea class="form-control" name="content" cols="30" rows="10" required minlength="5"
                    maxlength="20"></textarea>
            </div>

            <!-- 提交按钮 -->
            <button type="submit" class="btn btn-default">发表</button>
        </form>
    </div>
</body>

</html>

404.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>404</title>
</head>

<body>
    <h1 style="text-align: center;">404!!!!</h1>
</body>

</html>

演示图片

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1595040.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Hadoop+Spark大数据技术(微课版)曾国荪、曹洁版思维导图第四次作业 (第4章 HBase分布式DB)

1.简述Hbase的特点及与传统关系数据库的区别 HBase与传统关系数据库的区别 &#xff08;1&#xff09;数据类型 关系数据库具有丰富的数据类型&#xff0c;如字符串型、数值型、日期型、二进制型等。HBase只有字符串数据类型&#xff0c;数据的实际类型都是交由用户自己编写程序…

Spring+SpringMVC的知识总结

一:技术体系架构二:SpringFramework介绍三:Spring loC容器和核心概念3.1 组件和组件管理的概念3.1.1什么是组件:3.1.2:我们的期待3.1.3Spring充当组件管理角色(IOC)3.1.4 Spring优势3.2 Spring Ioc容器和容器实现3.2.1普通和复杂容器3.2.2 SpringIOC的容器介绍3.2.3 Spring IOC…

开源版中文和越南语贷款源码贷款平台下载 小额贷款系统 贷款源码运营版

后台 代理 前端均为vue源码&#xff0c;前端有中文和越南语 前端ui黄色大气&#xff0c;逻辑操作简单&#xff0c;注册可对接国际短信&#xff0c;可不对接 用户注册进去填写资料&#xff0c;后台审批&#xff0c;审批状态可自定义修改文字显示 源码免费下载地址抄笔记 (chaob…

【Vue】新手一步一步安装 vue 语言开发环境

文章目录 1、下载node.js安装包 1、下载node.js安装包 1.打开node.js的官网下载地址&#xff1a;http://nodejs.cn/download/ 选择适合自己系统的安装包&#xff1a;winds、mac 2. 配置node.js和npm环境变量 安装好之后&#xff0c;对npm安装的全局模块所在路径以及缓存所在路…

Linux网络基础 (二) ——(IP、MAC、端口号、TCPUDP协议、网络字节序)

文章目录 IP 地址基本概念源IP地址 & 目的IP地址 MAC 地址基本概念源MAC地址 & 目的MAC地址 端口号基本概念源端口号 & 目的端口号 TCP & UDP 协议基本概念TCP 与 UDP 的抉择 网络字节序大端、小端字节序 &#x1f396; 博主的CSDN主页&#xff1a;Ryan.Alask…

五、Jenkins、Docker、SpringClound持续集成

Jenkins、Docker、SpringClound持续集成 一、部署介绍1.部署图2.微服务项目结构3.项目启动顺序 二、微服务项目在Windows运行1.配置java、maven环境2.初始化数据库表/数据2.1 tensquare_gathering服务表2.2 tensquare_gathering服务表 3.启动微服务4.微服务接口测试4.1 获取用户…

Tomcat源码解析——Tomcat的启动流程

一、启动脚本 当我们在服务启动Tomcat时&#xff0c;都是通过执行startup.sh脚本启动。 在Tomcat的启动脚本startup.sh中&#xff0c;最终会去执行catalina.sh脚本&#xff0c;传递的参数是start。 在catalina.sh脚本中&#xff0c;前面是环境判断和初始化参数&#xff0c;最终…

架构师系列-搜索引擎ElasticSearch(六)- 映射

映射配置 在创建索引时&#xff0c;可以预先定义字段的类型&#xff08;映射类型&#xff09;及相关属性。 数据库建表的时候&#xff0c;我们DDL依据一般都会指定每个字段的存储类型&#xff0c;例如&#xff1a;varchar、int、datetime等&#xff0c;目的很明确&#xff0c;就…

45.HarmonyOS鸿蒙系统 App(ArkUI)创建列表(List)

列表是一种复杂的容器&#xff0c;当列表项达到一定数量&#xff0c;内容超过屏幕大小时&#xff0c;可以自动提供滚动功能。它适合用于呈现同类数据类型或数据类型集&#xff0c;例如图片和文本。在列表中显示数据集合是许多应用程序中的常见要求&#xff08;如通讯录、音乐列…

Qt快速入门(MV架构之TableView + QStandardItemModel + 自定义代理小案例)

Qt快速入门&#xff08;MV架构之TableView QStandardItemModel 自定义代理小案例&#xff09; 关于MV架构的简单介绍 在Qt框架中&#xff0c;代理&#xff08;Delegate&#xff09;、模型&#xff08;Model&#xff09;和视图&#xff08;View&#xff09;之间的关系构成了…

14_SpringMVC

文章目录 MVCSpringMVC与JavaEE对比SpringMVCSpringMVC的核心流程SpringMVC入门案例RequestMapping注解的使用Handler方法的返回值Handler方法的形参keyvalue形式的请求参数Json请求参数 RESTful风格接口静态资源处理FilterHandlerInterceptor异常处理SpringMVC核心流程流程图 …

自动化收集Unity版本更新日志

自动化收集Unity版本更新日志 &#x1f365;功能介绍&#x1f96a;食用手册填写配置开始搜集 &#x1f368;数据展示 &#x1f365;功能介绍 &#x1f4a1;获取指定年份中所有的Unity版本更新日志。 &#x1f4a1;根据指定字符串过滤。 &#x1f4a1;.收集后自动保存成markdow…

架构师系列-搜索引擎ElasticSearch(四)- 高级查询

ES查询 matchAll 脚本方式 该方式可以通过kabana、curl、elasticsearch-head&#xff08;纯前端&#xff09;去操作 # 默认情况下&#xff0c;es一次展示10条数据,通过from和size来控制分页 # 查询结果详解 GET goods/_search {"query": {"match_all":…

如何在MacOS上使用OpenHarmony SDK交叉编译?

本文以cJSON三方库为例介绍如何通过OpenHarmony的SDK在Mac平台进行交叉编译。 环境准备 SDK准备 我们可以通过 openHarmony SDK 官方发布渠道下载对应mac版本的SDK&#xff0c;当前OpenHarmony MAC版本的SDK有2种&#xff0c;一种是x86架构&#xff0c;另一种是arm64&#x…

二叉树例题分享

文章目录 二叉树例题分享[235. 二叉搜索树的最近公共祖先](https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/)[701. 二叉搜索树中的插入操作](https://leetcode.cn/problems/insert-into-a-binary-search-tree/)[108. 将有序数组转换为二叉搜索树…

分享一些有趣的 Linux 命令

1、sl 会显示一辆火车穿过你的终端屏幕 2、cmatrix 在终端中显示类似于《黑客帝国》电影中的绿色数字雨效果 3、fortune 显示一个随机的名人名言或者笑话 4、cowsay 让一头牛说出你输入的话 5、toilet 在终端中将输入的文本以艺术字体的形式呈现 6、figlet 类似于 toile…

Python数据分析案例41——基于CNN-BiLSTM的沪深300收盘价预测

案例背景 虽然我自己基于各种循环神经网络做时间序列的预测已经做烂了.....但是还是会有很多刚读研究生或者是别的领域过来的小白来问这些神经网络怎么写&#xff0c;怎么搭建&#xff0c;给我一篇论文看看感觉很厉害的样子。我一看&#xff1a;普刊、单变量时间序列预测、一个…

软考中级工程师网络技术第二节网络体系结构

OSPF将路由器连接的物理网络划分为以下4种类型&#xff0c;以太网属于&#xff08;25&#xff09;&#xff0c;X.25分组交换网属于&#xff08;非广播多址网络NBMA&#xff09;。 A 点对点网络 B 广播多址网络 C 点到多点网络 D 非广播多址网络 试题答案 正确答案&#xff1a; …

VS2019调试

最近开始了解单步调试 开始我按下F11键是没用的。 Visual Studio 调试快捷键失效_visual studio code用不了快捷键-CSDN博客 我的F11对应的系统功能是调小音量。 所以有两种模式&#xff1a; (1)按下F11,调小音量 (2)按下F11,单步调试 通过Fnesc键进行模式的切换。 还有一…

数据结构初阶:二叉树(二)

二叉树链式结构的实现 前置说明 在学习二叉树的基本操作前&#xff0c;需先要创建一棵二叉树&#xff0c;然后才能学习其相关的基本操作。由于现在对二叉树结构掌握还不够深入&#xff0c;为了降低学习成本&#xff0c;此处手动快速创建一棵简单的二叉树&#xff0c;快速进入二…