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

目录结构如下

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>

演示图片

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【无人机/平衡车/机器人】详解STM32+MPU6050姿态解算—卡尔曼滤波+四元数法+互补滤波(文末附3个算法源码)

效果: MPU6050姿态解算-卡尔曼滤波+四元数+互补滤波 目录 基础知识详解 欧拉角

【LeetCode】2635. 转换数组中的每个元素

转换数组中的每个元素 编写一个函数&#xff0c;这个函数接收一个整数数组 arr 和一个映射函数 fn&#xff0c;通过该映射函数返回一个新的数组。 返回数组的创建语句应为 returnedArray[i] fn(arr[i], i)。 请你在不使用内置方法 Array.map 的前提下解决这个问题。 示例 1:…

Python爬虫-京东商品评论数据

前言 本文是该专栏的第68篇,后面会持续分享python爬虫干货知识,记得关注。 在本专栏之前,笔者有详细介绍京东滑块验证码的解决方法,感兴趣的同学,可以直接翻阅文章《Python如何解决“京东滑块验证码”(5)》进行查看。 而本文,笔者以京东商品详情页的评论数据为例,通过…

【MySQL】索引篇

SueWakeup 个人主页&#xff1a;SueWakeup 系列专栏&#xff1a;学习技术栈 个性签名&#xff1a;保留赤子之心也许是种幸运吧 本文封面由 凯楠&#x1f4f8;友情提供 目录 本系列传送门 1. 什么是索引 2. 索引的特性 3. 索引的分类 4. 索引的优点及缺点 优点 缺点 5.…

全面的网络流量监控

流量监控指的是对数据流进行的监控&#xff0c;通常包括出数据、入数据的速度、总流量。通过网络流量监控&#xff0c;组织可以确保只有业务关键型流量通过网络传输&#xff0c;并限制不需要的网络流量&#xff0c;从而提高网络效率&#xff0c;又可以防止停机、减少 MTTR、帮助…

【氮化镓】微波脉冲对GaN HEMT失效的影响

本文是一篇关于高功率微波脉冲作用下GaN HEMT&#xff08;高电子迁移率晶体管&#xff09;热电多物理场耦合失效的实验研究。文章由Xiangdong Li等人撰写&#xff0c;发表在2023年11月的《IEEE Transactions on Electron Devices》上。文章通过实验研究了在高功率微波脉冲应力下…

英特尔推出中国特供版Gaudi 3芯片,性能暴降92%以应对美国出口管制|TodayAI

英特尔近期发布消息&#xff0c;其将在中国市场推出专为该地区定制的“特供版”Gaudi 3 AI芯片&#xff0c;以符合美国对AI芯片的出口管制。这一版本包括HL-328型号的OAM兼容夹层卡&#xff0c;预计将于6月24日发布&#xff1b;以及HL-388型号的PCIe加速卡&#xff0c;计划在9月…

(二十八)Flask之wtforms库【上手使用篇】

目录&#xff1a; 每篇前言&#xff1a;用户登录验证&#xff1a;用户注册验证&#xff1a;使用示例&#xff1a; 抽象解读使用wtforms编写的类&#xff1a;简单谈一嘴&#xff1a;开始抽象&#xff1a; 每篇前言&#xff1a; &#x1f3c6;&#x1f3c6;作者介绍&#xff1a;【…

L3 【哈工大_操作系统】操作系统启动

本节要点&#xff1a; 1、理解 OS 启动过程发生了什么&#xff0c;理解 OS 与 硬件 与 应用 之间的关系 2、本节讲解了 setup 模块 和 system 模块实现的功能 1、计算机上电时&#xff0c;操作系统在硬盘&#xff08;磁盘&#xff09;上&#xff0c;为了“取指执行”&#xff0…

Vite多环境配置与打包:灵活高效的Vue开发工作流

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

京东商品详情接口可以获取到那些数据?商品属性价格sku主图

京东商品详情接口可以获取到关于商品的丰富数据&#xff0c;包括但不限于以下内容&#xff1a; 商品基本信息&#xff1a;例如商品标题、价格、销量等。商品详情描述&#xff1a;这包括商品的详细描述、规格参数、包装清单等。商品评价信息&#xff1a;比如商品的好评率、评价…

图神经网络

图的性质 聚类系数 C i E i T i C_i \frac{E_i}{T_i} Ci​Ti​Ei​​ E i E_i Ei​表示节点 i i i的邻居实际存在的边的数量&#xff0c; T i T_i Ti​表示节点 i i i的邻居可能&#xff08;最多&#xff09;存在的边的数量 理论溯源 聚类系数这一概念首先源于论文“Colle…

OpenCV的查找命中或未命中

返回:OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇:OpenCV4.9更多形态转换 下一篇:OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 目标 在本教程中&#xff0c;您将学习如何使用 Hit-or-Miss 转换&#xff08;也称为 Hit-and-Miss 转…

已解决:前端直传阿里oss报错跨域问题,“No ‘Access-Control-Allow-Origin‘”,这个错误基本就是在阿里的开放平台没做规则配置(附我封装的上传源码)

解决方案&#xff08;我封装的上传代码在后面“封装上传”部分&#xff09;&#xff1a; 就直接上阿里oss管理后台去增加一个跨域规则&#xff1a;见图片&#xff0c;特详细 配置成这样点确定就好了&#xff0c;就这么简单 案发背景&#xff1a; 标题其实就已经是答案了&…

2024年第十五届蓝桥杯C/C++B组复盘(持续更新)

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《C》 《Linux》 《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 文章目录 试题A&#xff1a;握手问题问题描述思路 试题B&#xff1a;小球反弹问题描述思路…

【算法】字符串

个人主页 &#xff1a; zxctscl 如有转载请先通知 题目 1. 14. 最长公共前缀1.1 分析1.2 代码 2. 5. 最长回文子串2.1 分析2.2 代码 3. 67. 二进制求和3.1 分析3.2 代码 4. 43. 字符串相乘4.1 分析4.2 代码 1. 14. 最长公共前缀 1.1 分析 从第一个字符串开始两两比较&#xff…

LlamaIndex 文档 2

文章目录 一、构建 LLM 应用构建LLM 应用的关键步骤 二、使用LLM可用的LLM使用本地LLM Prompts 三、加载数据&#xff08;提取&#xff09;Loaders1、使用 SimpleDirectoryReader 加载2、使用 LlamaHub 的 Readers3、直接创建文档 转换 Transformations1、高级转换 API2、较低级…

Unity URP PBR_Cook-Torrance模型

Cook-Torrance模型是一个微表面光照模型&#xff0c;认为物体的表面可以看作是由许多个理想的镜面反射体微小平面组成的。 单点反射镜面反射漫反射占比*漫反射 漫反射 基础色/Π 镜面反射DFG/4(NV)(NL) D代表微平面分布函数&#xff0c;描述的是法线与半角向量normalize(L…

自编译支持CUDA硬解的OPENCV和FFMPEG

1 整体思路 查阅opencv的官方文档&#xff0c;可看到有个cudacodec扩展&#xff0c;用他可方便的进行编解码。唯一麻烦的是需要自行编译opencv。 同时&#xff0c;为了考虑后续方便&#xff0c;顺手编译了FFMPEG&#xff0c;并将其与OPENCV绑定。 在之前的博文“鲲鹏主机昇腾A…

帆软查询按钮,获取组件值。

【查询】按钮增加点击事件&#xff0c;通过_g().parameterEl.getWidgetByName(‘组件名’).getValue(); 获取组件值。 js脚本示例: var bm _g().parameterEl.getWidgetByName(bm).getValue(); if(!bm || bm.length 0 ) {alert ("没有选择部门&#xff0c;查询速度会很…