将HTML表单提交至Node.js处理后返回数据至指定页面的实现疑问
解决方法:在/search_result页面展示筛选后的菜谱结果
你现在遇到的核心问题是直接用res.json()把结果返回成纯文本JSON,浏览器自然就会直接显示这个原始文本。好在你已经配置了EJS模板引擎,正好可以用它来渲染美观的结果页面;如果想要无刷新体验,也可以用AJAX异步提交表单来动态展示结果。下面给你两种可行的方案:
方案一:服务器端渲染(基于EJS模板)
这是最贴合你现有配置的方式,无需额外前端框架就能实现页面跳转式的结果展示。
1. 先修正HTML表单的复选框问题
你原来的复选框name属性都设成了beef_roast,这样后端只能拿到最后一个选中的值,必须改成统一的name搭配不同的value,才能正确收集用户选中的食材:
<!DOCTYPE html> <html lang="en"> <head> <title>Recipes</title> </head> <body class="container"> <main> <form action="/search_result" method="post"> <input type="checkbox" name="ingredients" value="beef"> Beef <input type="checkbox" name="ingredients" value="pork"> Pork <input type="checkbox" name="ingredients" value="fish"> Fish <button type="submit" class="btn btn-default">Search recipe</button> </form> </main> </body> </html>
2. 准备菜谱JSON数据源
在项目根目录创建recipes.json文件,示例内容如下(你可以根据实际需求修改):
[ { "name": "家常炖牛肉", "link": "/recipes/beef-stew", "requiredIngredients": ["beef"] }, { "name": "香煎猪排", "link": "/recipes/pork-chop", "requiredIngredients": ["pork"] }, { "name": "柠檬烤鱼", "link": "/recipes/grilled-fish", "requiredIngredients": ["fish"] }, { "name": "海陆双拼饭", "link": "/recipes/meat-combo", "requiredIngredients": ["beef", "fish"] } ]
3. 修改Node.js路由逻辑
现在要读取JSON文件,根据用户选中的食材筛选菜谱,然后渲染EJS模板返回页面,而不是直接返回JSON:
var express = require('express'); var app = express(); const bodyParser = require("body-parser"); const fs = require('fs'); // 引入文件系统模块读取JSON app.set('view engine', 'ejs'); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); // 读取菜谱JSON数据的工具函数 const getRecipes = () => { const rawData = fs.readFileSync('./recipes.json', 'utf8'); return JSON.parse(rawData); }; // 首页路由(展示食材选择表单) app.get('/', function(req, res) { res.sendFile(__dirname + '/index.html'); // 假设你的HTML文件名为index.html }); // 处理表单提交,返回结果页面 app.post('/search_result', function(req, res) { // 处理用户未选中任何食材的情况,默认设为空数组 const selectedIngredients = req.body.ingredients || []; const allRecipes = getRecipes(); // 筛选逻辑:只保留所有必需食材都被用户选中的菜谱 const availableRecipes = allRecipes.filter(recipe => { return recipe.requiredIngredients.every(ing => selectedIngredients.includes(ing)); }); // 渲染EJS模板,把筛选后的菜谱数据传过去 res.render('search_result', { recipes: availableRecipes }); }); app.listen(3000, () => { console.log('服务器运行在端口3000'); });
4. 创建EJS结果模板
在项目根目录新建views文件夹(Express默认会从这里读取模板),然后创建search_result.ejs:
<!DOCTYPE html> <html lang="en"> <head> <title>菜谱搜索结果</title> </head> <body class="container"> <main> <h1>可用菜谱</h1> <% if (recipes.length === 0) { %> <p>没有找到符合你所选食材的菜谱哦~</p> <% } else { %> <ul> <% recipes.forEach(recipe => { %> <li><a href="<%= recipe.link %>"><%= recipe.name %></a></li> <% }) %> </ul> <% } %> <a href="/">返回食材选择页</a> </main> </body> </html>
这样提交表单后,服务器会自动完成筛选并渲染出格式化的结果页面,不再是纯文本JSON。
方案二:AJAX异步提交(无刷新展示结果)
如果想要页面不跳转,直接在当前页动态展示结果,可以用原生JS的fetch API实现:
1. 修改HTML表单(去掉跳转逻辑,添加结果展示区域)
<!DOCTYPE html> <html lang="en"> <head> <title>Recipes</title> </head> <body class="container"> <main> <form id="ingredientForm"> <input type="checkbox" name="ingredients" value="beef"> Beef <input type="checkbox" name="ingredients" value="pork"> Pork <input type="checkbox" name="ingredients" value="fish"> Fish <button type="submit" class="btn btn-default">Search recipe</button> </form> <!-- 用来动态展示结果的区域 --> <div id="recipeResults"></div> </main> <script> // 监听表单提交事件 document.getElementById('ingredientForm').addEventListener('submit', async function(e) { e.preventDefault(); // 阻止表单默认跳转行为 // 收集用户选中的食材 const formData = new FormData(this); const ingredients = Array.from(formData.getAll('ingredients')); // 发送异步POST请求到服务器 const response = await fetch('/search_recipes', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ingredients }) }); const recipes = await response.json(); // 动态渲染结果到页面 const resultsDiv = document.getElementById('recipeResults'); if (recipes.length === 0) { resultsDiv.innerHTML = '<p>没有找到符合你所选食材的菜谱哦~</p>'; } else { const recipeList = recipes.map(recipe => `<li><a href="${recipe.link}">${recipe.name}</a></li>`).join(''); resultsDiv.innerHTML = `<h1>可用菜谱</h1><ul>${recipeList}</ul>`; } }); </script> </body> </html>
2. 修改Node.js路由(新增处理AJAX请求的接口)
var express = require('express'); var app = express(); const bodyParser = require("body-parser"); const fs = require('fs'); app.set('view engine', 'ejs'); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); const getRecipes = () => { const rawData = fs.readFileSync('./recipes.json', 'utf8'); return JSON.parse(rawData); }; // 首页路由 app.get('/', function(req, res) { res.sendFile(__dirname + '/index.html'); }); // 处理AJAX请求的接口,返回JSON格式的筛选结果 app.post('/search_recipes', function(req, res) { const selectedIngredients = req.body.ingredients || []; const allRecipes = getRecipes(); const availableRecipes = allRecipes.filter(recipe => { return recipe.requiredIngredients.every(ing => selectedIngredients.includes(ing)); }); res.json(availableRecipes); }); app.listen(3000, () => { console.log('服务器运行在端口3000'); });
这样用户点击搜索按钮后,页面不会跳转,而是在当前页面动态加载并展示结果,体验更流畅。
内容的提问来源于stack exchange,提问作者rmarques
相关产品推荐
相关产品推荐

