如何用Express与HTML实现带ID跳转的动态列表?
问题排查与修复:从JSON生成动态列表并实现详情跳转
核心问题梳理
你需要实现从JSON数据生成动态列表,点击列表项跳转到对应详情页,但当前代码存在多处语法错误、逻辑问题,导致功能失效。以下是逐部分的问题排查和修正方案:
1. Express API 代码问题与优化
存在的小问题
- JSON文件中有两个
id=3的条目,会导致/tours/:id接口返回第一个匹配项,详情查询逻辑混乱 - 直接使用绝对路径返回HTML文件,可改为相对路径(需确保文件结构合理)
修正后的Express代码
import express from "express"; import tours from "./tours_file/tours.json" assert { type: "json" }; import path from 'path'; const app = express(); const PORT = 3000; // 静态文件托管(可选,若需直接访问静态资源) app.use(express.static(path.join(__dirname, 'public'))); app.get("/", (req, res) => { // 使用相对路径,避免硬编码绝对路径 res.sendFile(path.join(__dirname, 'homepage.html')); }); // 获取所有tour app.get("/tours", (req, res) => { res.json(tours); }); // 根据ID获取单个tour app.get("/tours/:id", (req, res) => { const { id } = req.params; const tour = tours.find((tour) => tour.id === id); if (tour) { res.json(tour); } else { res.status(404).json({ message: "Tour not found" }); } }); app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); });
2. HTML及脚本代码问题与修复
这部分是功能失效的核心,存在多处语法和逻辑错误:
const ul = document.createElement;未调用创建元素的方法,应为document.createElement('ul')- 请求路径错误:直接请求
tours.json而非Express提供的/tours接口 output.textContent = "ready"会覆盖已添加的子元素,破坏DOM结构- 循环遍历错误:
arr.array.forEach应为arr.forEach,且变量名不统一(element和el混用) - JSON数据中无
status字段,状态类判断无效 - 未实现点击跳转到详情的逻辑
修正后的HTML代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Homepage</title> <style> .tour-item { color: grey; font-weight: 100; cursor: pointer; margin: 8px 0; padding: 4px; list-style: none; } .tour-item:hover { color: gainsboro; font-weight: bold; background-color: #f0f0f0; } .tour-list { padding-left: 0; } </style> </head> <body> <h1>Homepage</h1> <p>scegli o aggiungi un tour</p> <div class="output"></div> <script> const output = document.querySelector(".output"); const tourList = document.createElement('ul'); tourList.classList.add('tour-list'); output.append(tourList); window.addEventListener("DOMContentLoaded", () => { output.insertAdjacentText('afterbegin', '加载中...'); loadData(); }); function loadData() { // 请求Express的API接口 fetch("/tours") .then((rep) => { if (!rep.ok) throw new Error('请求失败'); return rep.json(); }) .then((data) => { output.removeChild(output.firstChild); // 移除加载提示 addToPage(data); }) .catch(err => { output.textContent = `加载失败: ${err.message}`; }); } function addToPage(tours) { tours.forEach((tour) => { const li = document.createElement("li"); li.classList.add('tour-item'); li.textContent = `${tour.name} (${tour.country})`; // 存储tour ID,用于跳转 li.dataset.tourId = tour.id; // 点击跳转到详情(这里可以改为跳转到详情页,或弹窗显示详情) li.addEventListener("click", () => { // 示例:跳转到详情接口,或打开新页面展示详情 window.open(`/tours/${tour.id}`, '_blank'); // 若要在当前页面展示详情,可发起fetch请求后渲染内容 }); tourList.append(li); }); } </script> </body> </html>
3. JSON文件问题修复
- 最后一个条目的
description字段未闭合,存在语法错误 - 两个条目
id=3,需修改为唯一ID(比如改为4)
修正后的JSON代码
[ { "id": "1", "name": "The Forest Hiker", "difficulty": "easy", "country": "Trentino", "description": "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." }, { "id": "2", "name": "The Alpinist", "difficulty": "hard", "country": "Svizzera", "description": "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." }, { "id": "3", "name": "A Bicycle Trip", "difficulty": "easy", "country": "Sicilia", "description": "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." }, { "id": "4", "name": "Horse Trip", "difficulty": "easy", "country": "Francia", "description": "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur." } ]
运行说明
- 确保所有文件路径正确:Express入口文件、HTML文件、JSON文件的相对路径匹配
- 启动Express服务:
node your-server-file.js - 访问
http://localhost:3000即可看到动态生成的列表,点击列表项会打开对应详情接口页面
内容的提问来源于stack exchange,提问作者Malinowa
相关产品推荐
相关产品推荐

