Node.js CRUD应用中如何实现无刷新跨页面数据传递?
问题:Node.js CRUD应用无法无刷新传递数据
我基于Node.js、Express、Handlebars和MySQL开发的CRUD应用功能正常,但尝试在不刷新目标页面的情况下传递数据时完全没效果,已经卡了3天。以下是相关代码:
主页代码(Handlebars+HTML)
{{#if removedUser}} <div class="alert alert-success alert-dismissible fade show" role="alert"> User has been removed. <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> </div> {{/if}} <div class="row"> <div class="col-6"> <h1>Users</h1> </div> <div class="col-6 d-flex justify-content-end"> <a href="/adduser" type="button" class="btn btn-primary align-self-center">+ add user</a> </div> </div> <table class="table table-bordered"> <thead class="thead-dark"> <tr> <th scope="col">#</th> <th scope="col">First Name</th> <th scope="col">Last Name</th> <th scope="col">Email</th> <th scope="col">Credits</th> <th scope="col" class="text-end">Action</th> </tr> </thead> <tbody> {{#each rows}} <tr> <th scope="row">{{this.id}}</th> <td>{{this.first_name}}</td> <td>{{this.last_name}}</td> <td>{{this.email}}</td> <td>{{this.credits}}</td> <td class="text-end"> <div class="input-group input-group-sm mb-3"> <form action="/credits/{{this.id}}" method="post"> <input type="number" class="form-control" placeholder="Credits" name="input_credits" id="input_credits" aria-label="Sizing example input" aria-describedby="inputGroup-sizing-sm"> <div class="col-12 d-grid"> <!-- 修复input与button标签嵌套错误 --> <button class="bi bi-plus" id="post_comment" type="submit">Add</button> </div> </form> </div> <a href="/viewuser/{{this.id}}" type="button" class="btn btn-light btn-small"><i class="bi bi-eye"></i> View</a> <a href="/edituser/{{this.id}}" type="button" class="btn btn-light btn-small"><i class="bi bi-pencil"></i> Edit</a> </td> </tr> {{/each}} <!-- 修正{{this.credits}}无法取值问题,添加用户ID参数 --> <a href="/label?userId=4" type="button" class="btn btn-primary align-self-center">View Credits Label</a> </tbody> </table> <!-- 修复未闭合的script标签 --> <script src="/javascripts/jquery-1.6.4.min.js"></script> <script src="/javascripts/script.js"></script>
目标页面(label页面)代码
<div class="row"> <span class="label label-default" id="set_input" name="set_input">Loading...</span> </div> <!-- 修复路径与标签未闭合问题 --> <script src="/javascripts/jquery-1.6.4.min.js"></script> <script src="/javascripts/script.js"></script>
CRUD操作代码(Node.js)
const mysql = require('mysql'); // Connection Pool let connection = mysql.createConnection({ host: process.env.DB_HOST, user: process.env.DB_USER, password: process.env.DB_PASS, database: process.env.DB_NAME }); // View Users exports.view = (req, res) => { connection.query('SELECT * FROM user WHERE status = "active"', (err, rows) => { if (!err) { let removedUser = req.query.removed; res.render('home', { rows, removedUser }); } else { console.log(err); } console.log('The data from user table: ', rows); }); } // Find User by Search exports.find = (req, res) => { let searchTerm = req.body.search; connection.query('SELECT * FROM user WHERE first_name LIKE ? OR last_name LIKE ?', ['%' + searchTerm + '%', '%' + searchTerm + '%'], (err, rows) => { if (!err) { res.render('home', { rows }); } else { console.log(err); } console.log('The data from user table: ', rows); }); } exports.form = (req, res) => { res.render('add-user'); } // Add new user exports.create = (req, res) => { const { first_name, last_name, email, credits, comments } = req.body; connection.query('INSERT INTO user SET first_name = ?, last_name = ?, email = ?, credits = ?, comments = ?', [first_name, last_name, email, credits, comments], (err, rows) => { if (!err) { res.render('add-user', { alert: 'User added successfully.' }); } else { console.log(err); } console.log('The data from user table: ', rows); }); } // Edit user exports.edit = (req, res) => { connection.query('SELECT * FROM user WHERE id = ?', [req.params.id], (err, rows) => { if (!err) { res.render('edit-user', { rows }); } else { console.log(err); } console.log('The data from user table: ', rows); }); } // Update User exports.update = (req, res) => { const { first_name, last_name, email, credits, comments } = req.body; connection.query('UPDATE user SET first_name = ?, last_name = ?, email = ?, credits = ?, comments = ? WHERE id = ?', [first_name, last_name, email, credits, comments, req.params.id], (err, rows) => { if (!err) { connection.query('SELECT * FROM user WHERE id = ?', [req.params.id], (err, rows) => { if (!err) { res.render('edit-user', { rows, alert: `${first_name} has been updated.` }); } else { console.log(err); } console.log('The data from user table: ', rows); }); } else { console.log(err); } console.log('The data from user table: ', rows); }); } // Delete User exports.delete = (req, res) => { connection.query('DELETE FROM user WHERE id = ?', [req.params.id], (err, rows) => { if(!err) { let removedUser = encodeURIComponent('User succesefully removed'); res.redirect('/?removed=' + removedUser); } else { console.log(err); } console.log('The data from user table: ', rows); }); } // View Users exports.viewall = (req, res) => { connection.query('SELECT * FROM user WHERE id = ?', [req.params.id], (err, rows) => { if (!err) { res.render('view-user', { rows }); } else { console.log(err); } console.log('The data from user table: ', rows); }); } // 新增:获取用户积分的API接口 exports.getCredits = (req, res) => { connection.query('SELECT credits FROM user WHERE id = ?', [req.params.id], (err, rows) => { if (!err) { res.json({ success: true, credits: rows[0].credits }); } else { console.log(err); res.json({ success: false, error: err.message }); } }); } // 修改:更新积分后返回JSON,支持无刷新操作 exports.credits = (req, res) => { const credits = req.body.input_credits * 100; connection.query('UPDATE user SET credits = ? WHERE id = ?', [credits, req.params.id], (err, result) => { if (!err) { connection.query('SELECT credits FROM user WHERE id = ?', [req.params.id], (err, rows) => { if (!err) { res.json({ success: true, credits: rows[0].credits }); } else { console.log(err); res.json({ success: false, error: err.message }); } }); } else { console.log(err); res.json({ success: false, error: err.message }); } }); }
解决思路与实现
当前代码依赖服务端渲染和页面重定向,要实现无刷新传数据,必须用AJAX异步请求+前端DOM更新方案,步骤如下:
1. 注册新增的API路由
在Express主文件中添加:
const crud = require('./path/to/your/crud/file'); // 新增获取积分的API app.get('/api/credits/:id', crud.getCredits); // 保留原更新路由,现在返回JSON app.post('/credits/:id', crud.credits);
2. 前端AJAX提交表单(主页script.js)
// 监听积分更新表单的提交事件 $('form[action^="/credits/"]').submit(function(e) { e.preventDefault(); // 阻止默认刷新提交 const $form = $(this); const userId = $form.attr('action').split('/')[2]; const inputVal = $form.find('input[name="input_credits"]').val(); if (!inputVal || isNaN(inputVal)) { alert('请输入有效的数字'); return; } $.ajax({ url: $form.attr('action'), method: 'POST', data: { input_credits: inputVal }, dataType: 'json', success: function(res) { if (res.success) { // 更新当前页面的积分显示 $form.closest('tr').find('td:eq(4)').text(res.credits); // 存储到本地存储,供目标页面监听 localStorage.setItem(`user_${userId}_credits`, res.credits); alert('积分更新成功'); } else { alert('更新失败:' + res.error); } }, error: function() { alert('服务器错误,请稍后重试'); } }); });
3. 目标页面无刷新获取数据(script.js)
$(document).ready(function() { // 从URL参数获取目标用户ID const urlParams = new URLSearchParams(window.location.search); const targetUserId = urlParams.get('userId') || 4; // 默认ID为4 // 加载积分数据 function loadUserCredits() { $.ajax({ url: `/api/credits/${targetUserId}`, method: 'GET', dataType: 'json', success: function(res) { if (res.success) { $('#set_input').text(res.credits); } else { $('#set_input').text('加载失败'); } }, error: function() { $('#set_input').text('服务器连接失败'); } }); } // 页面初始化加载 loadUserCredits(); // 每隔5秒自动刷新(可选) setInterval(loadUserCredits, 5000); // 监听本地存储变化,实时更新 window.addEventListener('storage', function(e) { if (e.key === `user_${targetUserId}_credits`) { $('#set_input').text(e.newValue); } }); });
4. 其他代码修正
- 修复了主页表单按钮的标签嵌套错误
- 修正了脚本标签未闭合问题
- 调整了Label按钮链接,添加用户ID参数
- 删除了原label路由中无效的服务端DOM操作代码
内容的提问来源于stack exchange,提问作者Straqpy
相关产品推荐
相关产品推荐

