You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用JavaScript渲染CSV表格失败问题排查与修复求助

问题描述

作为前端开发新手,我在实现网页展示CSV为美观表格时遇到问题:访问本地端口时页面完全不显示表格内容。打开开发者工具Network标签可见,GET /data请求返回200状态码,响应类型为JSON且能看到JSON主体;服务器日志显示sending data in res.json,但script.js中没有任何fetch相关日志,显然fetchAndRenderCSV函数从未执行。请问问题出在哪里?该如何修复?


相关代码

script.js

// Function to fetch CSV data from the server and render it as a table
const fetchAndRenderCSV = async () => {
    try {
        console.log('trying fetch /data')
        const response = await fetch('/data');
        console.log('Response is: ' + response)
        const csvData = await response.json();
        console.log(csvData)
        renderCSVTable(csvData);
    } catch (error) {
        console.error('Error fetching CSV data:', error);
    }
};

// Function to render CSV data as a table
const renderCSVTable = (data) => {
    const tableContainer = document.getElementById('csvTableContainer');
    const tableHTML = generateTableHTML(data);
    tableContainer.innerHTML = tableHTML;
};

// Function to generate HTML for the table
const generateTableHTML = (data) => {
    let tableHTML = '<table>';
    // Assuming the first row contains headers
    tableHTML += '<tr>';
    for (let i = 0; i < data[0].length; i++) {
        tableHTML += `<th>${data[0][i]}</th>`;
    }
    tableHTML += '</tr>';

    // Add rows for each data entry (excluding the header row)
    for (let i = 1; i < data.length; i++) {
        tableHTML += '<tr>';
        for (let j = 0; j < data[i].length; j++) {
            tableHTML += `<td>${data[i][j]}</td>`;
        }
        tableHTML += '</tr>';
    }

    tableHTML += '</table>';
    return tableHTML;
};

const submitGuess = async () => {
try {
    // Clear result and error messages
    resultMessage.textContent = '';
    errorMessage.textContent = '';

    const inputValue = userInput.value.trim();
    if (inputValue === '') {
        errorMessage.textContent = 'Please enter a name before submitting.';
        return;
    }

    const response = await fetch('/handleInput', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({ userInput: inputValue }),
    });

    const data = await response.json();

    if (data.isCorrect) {
        resultMessage.textContent = 'Correct answer!';
        resultMessage.classList.add('correct-answer');
    } else {
        // Shake animation on incorrect guess
        userInput.classList.add('shake');

        // Remove the 'shake' class after the animation ends
        userInput.addEventListener('animationend', () => {
            userInput.classList.remove('shake');
        });

        resultMessage.textContent = 'Incorrect answer.';
        resultMessage.classList.remove('correct-answer'); // Remove the class if present
    }

    userInput.value = '';
} catch (error) {
    console.error('Error:', error);
}
};

// Call the function to fetch and render CSV data when the page loads
console.log('fetch')
fetchAndRenderCSV();

styles.css

body {
  font-family: Arial, sans-serif;
  text-align: center;
}

#game {
  margin: 20px auto;
  max-width: 400px;
}

#word {
  font-size: 2em;
  margin-bottom: 20px;
}

#guess {
  padding: 5px;
  font-size: 1.2em;
  width: 100px;
  margin-bottom: 10px;
}

#feedback {
  margin-top: 20px;
  font-weight: bold;
}

@keyframes shake {
  0% {
    transform: translateX(0);
  }
  25% {
    transform: translateX(-5px);
  }
  50% {
    transform: translateX(5px);
  }
  75% {
    transform: translateX(-5px);
  }
  100% {
    transform: translateX(0);
  }
}

.shake {
  animation: shake 0.4s ease-in-out;
}

index.html

<h1>Guess</h1>

<div id="csvTableContainer"></div>
<!-- This is where the table will be rendered -->

<form id="guessForm">
  <label for="userInput">Enter Guess:</label>
  <input type="text" id="userInput" name="userInput" required>
  <button type="button" onclick="submitGuess()" id="submitButton">Submit</button>
</form>

<button onclick="playAgain()" id="playAgainButton">Play Again</button>

<!-- Result message with inline style for correct answer -->
<p id="resultMessage" style="color: green;"></p>

<!-- Error message -->
<p id="errorMessage" style="color: red;"></p>

server.js

const puppeteer = require('puppeteer');
const fs = require('fs');
const Papa = require('papaparse');
// const Parse = require('parse');
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const { spawn } = require('child_process');

const app = express();
const port = 3000;

app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());

let isCorrect = false;
let answer, filePath;

app.get('/data', (req, res) => {
    try {
        // Read CSV file
        const csvData = fs.readFileSync(filePath, 'utf8');

        // Parse CSV data
        const parsedData = Papa.parse(csvData, { header: true }).data;

        // Send parsed CSV data as JSON
        console.log('sending data in res.json')
        const ret = res.json(parsedData);
        // console.log(ret)
    } catch (error) {
        console.error('Error reading or parsing CSV file:', error);
        res.status(500).send('Internal Server Error');
    }
});


app.listen(port, () => {
    console.log(`Server is running at http://localhost:${port}`);
    generateCorrectAnswer();
    console.log('The correct answer is: ', answer)
    console.log('filePath is: ' + filePath)
    checkFileExists(filePath)
    readAndParseCSV(filePath);
});

问题原因及修复方案

核心原因

  1. script.js未引入到页面:index.html里没有加载script.js的标签,导致所有JS代码都没执行,包括fetchAndRenderCSV函数。
  2. 前后端数据格式不匹配:服务器用Papa.parse的header: true选项,返回的是对象数组(每个元素是带表头键的对象),但前端generateTableHTML函数是按二维数组编写的,即使JS加载也会报错。
  3. 未定义playAgain函数:index.html里有onclick="playAgain()",但script.js中没有这个函数,会抛出错误中断其他代码执行。
  4. 服务器filePath未赋值:服务器里filePath变量只声明未赋值,会导致读取CSV文件失败。

修复步骤

1. 在index.html中引入静态资源

在index.html的</body>标签前添加以下代码,确保加载样式和脚本:

<link rel="stylesheet" href="styles.css">
<script src="script.js"></script>

注意:确保script.js、styles.css和CSV文件都放在服务器配置的public文件夹下(因为服务器用了app.use(express.static(path.join(__dirname, 'public'))))。

2. 适配前端数据处理逻辑

修改generateTableHTML函数,适配服务器返回的对象数组格式:

const generateTableHTML = (data) => {
    // 处理空数据情况
    if (!data || data.length === 0) return '<p>暂无数据</p>';
    
    // 获取表头(取第一个对象的所有键)
    const headers = Object.keys(data[0]);
    let tableHTML = '<table border="1" cellpadding="8" cellspacing="0">';
    
    // 生成表头行
    tableHTML += '<tr>';
    headers.forEach(header => {
        tableHTML += `<th>${header}</th>`;
    });
    tableHTML += '</tr>';
    
    // 生成数据行
    data.forEach(row => {
        tableHTML += '<tr>';
        headers.forEach(header => {
            // 处理空值,避免显示undefined
            tableHTML += `<td>${row[header] || ''}</td>`;
        });
        tableHTML += '</tr>';
    });
    
    tableHTML += '</table>';
    return tableHTML;
};

额外给table加了基础样式,让表格更美观。

3. 补充playAgain函数

在script.js末尾添加该函数,避免报错:

const playAgain = () => {
    // 重置游戏状态
    userInput.value = '';
    resultMessage.textContent = '';
    errorMessage.textContent = '';
};

4. 服务器中赋值filePath

在generateCorrectAnswer函数中(或者服务器启动时)给filePath赋值,指向你的CSV文件路径,比如:

// 示例:假设CSV文件在public文件夹下名为data.csv
filePath = path.join(__dirname, 'public', 'data.csv');

确保该路径下存在有效的CSV文件,否则会抛出读取错误。


内容的提问来源于stack exchange,提问作者contactme8359

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 11:27:32