NodeJs实战-待办列表(3)-前端页面填充待办数据

本文介绍了一个使用Node.js实现的待办事项列表应用。该应用通过前后端分离技术,利用Ajax进行数据交互,实现了待办事项的添加、查询及完成等功能。前端采用jQuery操作DOM元素,后端提供JSON数据接口。

为啥在前端填充待办数据?

第2节的页面数据在后台填充的,这样有个问题,每次待办列表发生变化,都需要重新返回页面,导致每次更新待办都要返回整个页面

如何在前端填充待办数据?

需要了解的知识

  1. ajax 发送http请求
  2. jQuery操作DOM元素增删改查

页面修改

    • 标签增加 id,后续操作DOM时需要使用这个id
<ul id="todo_ul"></ul>
  1. 页面初始化的时候,使用 ajax 发送请求,获取后端服务的待办数据
        function init() {
            $.ajax({
                url: "/query",
                method: 'GET',
                success: function(result) {
                    initUlData(result);
                }
            });
        }
  1. 服务端返回 result 数据,前端页面绘制填充待办数据
        function initUlData(result) {
            if (result.code == '0') {
                alert(result.msg);
            } else {
                $('#todo_ul').empty();
                if (result.data == null) {
                    alert('服务器返回数据为空');
                    return ;
                }
                result.data.forEach(a => {
                    $('#todo_ul').append( $('<li></li>').html(a));
                });
            }
        }
  1. 页面初始化的时候调用 init() 方法
$(function() {
   init();
}
  1. 完整的 index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>待办列表</title>
    <script type="text/javascript" src="https://code.jquery.com/jquery-3.6.1.min.js"></script>
    <script type="text/javascript">
        $(function() {
            init();
            $("#add").on('click', function(){
                add();
            });
            $("#complete").on('click', function(){
                complete();
            });
        });

        
        function init() {
            $.ajax({
                url: "/query",
                method: 'GET',
                success: function(result) {
                    initUlData(result);
                }
            });
        }

        function add() {
            var item = $("#item_text").val().trim();
            if (item.length == 0) {
                alert('输入数据不能为空');
            }
            $.ajax({
                url: "/add",
                method: 'GET',
                data: {
                    item: item
                },
                success: function(result) {
                    initUlData(result);
                }
            });
        }

        function complete() {
            var item = $("#item_text").val().trim();
            if (item.length == 0) {
                alert('输入数据不能为空');
            }
            $.ajax({
                url: "/complete",
                method: 'GET',
                data: {
                    item: item
                },
                success: function(result) {
                    initUlData(result);
                }
            });
        }

        function initUlData(result) {
            if (result.code == '0') {
                alert(result.msg);
            } else {
                $('#todo_ul').empty();
                if (result.data == null) {
                    alert('服务器返回数据为空');
                    return ;
                }
                result.data.forEach(a => {
                    $('#todo_ul').append( $('<li></li>').html(a));
                });
                focusItemText();
            }
        }

        function focusItemText() {
            $('#item_text').val('');
            $('#item_text').focus();
        }
    </script>
</head>
<body>
    <h1>待办列表</h1>
    <form method="post" >
        <p><input id="item_text" type="text" name="item" /></p>
        <p><input id="add" type="button" value="添加" /></p>
        <p><input id="complete" type="button" value="完成" /></p>
    </form>
    <ul id="todo_ul"></ul>
</body>
</html>

后端服务封装数据返回

后端服务用json数据返回给前端,json结构清晰,前端解析json比较方便。

server.js 修改

  1. 增加对象用于存储返回数据
let retData = {
	'code':'',
	'data': [],
	'msg':''
}

如何把对象变成字符串?
打开浏览器开发者工具 console 试试
在这里插入图片描述
2. 增加服务器输出json方法

function sendMsg(response, msg) {
	response.writeHead(200, {'Content-Type': 'application/json;charset=UTF-8'});
    response.write(msg);
    response.end();
}

注意:需要指定 Content-Type 为 application/json

  1. 修改 readFile 逻辑,不需要填充数据了,刷新才返回页面
function readFile(response, filePath) {
	fs.readFile(filePath, (err, data) => {
		if (err) {
			return send404(response);
		}
		var html = data.toString();
		response.writeHead(200, {'Content-Type': 'text/html'});
		response.end(html);
	});
}
  1. 增加 /query,/ 的执行逻辑方法
const server = http.createServer((request, response) => {
	var urlParse = parse(request.url);
	var urlPath = urlParse.pathname;
	switch (urlPath) {
		case '/':
			var filePath = 'public/index.html';
    		var absPath = './' + filePath;
			readFile(response, absPath);
			break;
		case '/query':
			sendMsg();
			break;
		case '/add':
			sendMsg();
			break;
		case '/complete':
			sendMsg();
			break;
	}
	
});

服务端修改成只有读取首页的时候才加载 HTML 页面,访问其它地址就返回 json 数据

  1. 完整的 server.js 代码
const http = require('http');
const fs = require('fs');
const parse = require('url').parse;

const hostname = '127.0.0.1';
const port = 3000;

const CODE_ERROR = 0;
const CODE_SUCCESS = 1;

var todoSet = new Set();

function send404(response) {
    response.writeHead(404, {'Content-Type': 'text/plain'});
    response.write('Error 404: resource not found.');
    response.end();
}

function sendMsg(response, msg) {
	response.writeHead(200, {'Content-Type': 'application/json;charset=UTF-8'});
    response.write(msg);
    response.end();
}

function readFile(response, filePath) {
	fs.readFile(filePath, (err, data) => {
		if (err) {
			return send404(response);
		}
		var html = data.toString();
		// html = html.replace('%', Array.from(todoSet).join('</li><li>'));
		response.writeHead(200, {'Content-Type': 'text/html'});
		response.end(html);
	});
}

function add(itemData) {
	todoSet.add(itemData);
}

function complete(itemData) {
	// 判断待办事项是否已添加
	if (!todoSet.has(itemData)) {
		return itemData + '-待办事项不存在';
	}
	if (todoSet.delete(itemData)) {
		return true;
	}
	return itemData + '-待办事项删除失败';
}

function findItemData(urlParse) {
	if (urlParse.query.length > 0) {
		var queryArray = urlParse.query.split('=');
		if (queryArray.length >= 2) {
			return queryArray[1];
		}
	}
	return '';
}

function buildData(code, data, msg) {
    // 返回数据
	let retData = {
		'code':'',
		'data': [],
		'msg':''
	}
	retData.code = code;
	retData.data = data;
	retData.msg = msg;
	return retData;
}

const server = http.createServer((request, response) => {
	var urlParse = parse(request.url);
	var urlPath = urlParse.pathname;
	var itemData;
	if (urlPath == '/add' || urlPath == '/complete') {
		itemData = findItemData(urlParse);
		if (itemData.length == 0) {
			var data = buildData(CODE_ERROR, [], '输入数据有误');
			return sendMsg(response, JSON.stringify(data));
		}
	}
	switch (urlPath) {
		case '/':
			var filePath = 'public/index.html';
    		var absPath = './' + filePath;
			readFile(response, absPath);
			break;
		case '/query':
			var data = buildData(CODE_SUCCESS, Array.from(todoSet), '页面初始化');
			sendMsg(response, JSON.stringify(data));
			break;
		case '/add':
			add(itemData);
			var data = buildData(CODE_SUCCESS, Array.from(todoSet), '添加成功');
			sendMsg(response, JSON.stringify(data));
			break;
		case '/complete':
			var res = complete(itemData)
			if (res == true) {
				var data = buildData(CODE_SUCCESS, Array.from(todoSet), '待办已完成');
				return sendMsg(response, JSON.stringify(data)); 
			}
			var data = buildData(CODE_ERROR, [], res);
			sendMsg(response, JSON.stringify(data));
			break;
	}
});

server.listen(port, hostname, () => {
	console.log(`Server running at http://${hostname}:${port}/`)
})

效果图

执行 node server.js 启动服务

F:\Github\Nodejs\todolist>node server.js
Server running at http://127.0.0.1:3000/

初始化页面

在这里插入图片描述

添加待办事项

  1. 添加 111
  2. 添加 en111
  3. 添加 中文111
    在这里插入图片描述
    发现有个小问题,中文乱码了,后续处理

完成待办事项

  1. 完成 111
  2. 完成 中文111
    在这里插入图片描述
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Chengdu.S

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值