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

无需jQuery:从表单生成表格行并保存至JSON(Electron环境)

问题描述

在Electron环境开发应用,尝试实现无jQuery功能:从表单获取用户输入生成新表格行,同时将数据保存到JSON文件避免页面刷新后丢失。目前存在两个核心问题:

  1. 新增的表格行瞬间消失
  2. 单元格内容显示为[object HTMLInputElement]

问题原因及解决方案

1. 新增行瞬间消失

表单内的<button>默认是submit类型,点击后会触发表单提交行为,导致页面刷新,新增的行因此被重置。

  • 解决方法:在表单提交时阻止默认刷新行为,可通过两种方式实现:
    • 修改按钮类型为button(<button type="button">Submit</button>)
    • 在处理函数中调用事件对象的preventDefault()方法

2. 单元格显示[object HTMLInputElement]

当前代码直接将DOM输入元素对象赋值给单元格的innerHTML,而非获取用户输入的内容。需要读取输入框的value属性拿到实际输入值。

3. JSON文件保存的额外问题

直接使用fs.appendFile会导致JSON格式混乱(多次追加会生成无效JSON),正确做法是先读取现有数据,添加新条目后再整体写入文件。同时注意Electron渲染进程的fs使用限制(默认需通过主进程代理或开启nodeIntegration)。


修改后的完整代码

renderer.js

const fs = require('fs');
const path = require('path');
// 建议使用Electron提供的用户数据目录存储文件,避免权限问题
const dataPath = path.join(__dirname, 'table-data.json');

const addTableRow = (e) => {
    // 阻止表单默认提交行为,解决页面刷新问题
    e.preventDefault();

    // 获取输入框的实际值,而非DOM元素本身
    const name = document.getElementById("name").value;
    const pnum = document.getElementById("pnum").value;
    const age = document.getElementById("age").value;

    // 插入行到表格tbody中(更规范的操作方式)
    const tableBody = document.getElementById("clientTable").querySelector('tbody');
    const row = tableBody.insertRow(-1);

    const c1 = row.insertCell(0);
    const c2 = row.insertCell(1);
    const c3 = row.insertCell(2);

    // 设置单元格内容为用户输入值
    c1.textContent = name;
    c2.textContent = pnum;
    c3.textContent = age;

    // 读取现有数据并添加新条目
    let clients = [];
    try {
        const existingData = fs.readFileSync(dataPath, 'utf8');
        clients = JSON.parse(existingData);
    } catch (err) {
        // 文件不存在时初始化空数组
        console.log('数据文件不存在,将创建新文件');
    }
    clients.push({ name, pnum, age });

    // 写入文件,保证JSON格式正确
    fs.writeFileSync(dataPath, JSON.stringify(clients, null, 2));

    // 清空表单输入
    document.getElementById("clForm").reset();
}

// 用事件监听绑定替代inline onclick,更符合现代JS规范
document.addEventListener('DOMContentLoaded', () => {
    const form = document.getElementById("clForm");
    form.addEventListener('submit', addTableRow);
});

index.html(核心修改部分)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="app.css">
    <title>Ezek's jsapp</title>
</head>
<body>
    <div class="tabs-container">
        <div class="tabs">
            <div class="tab active">Clients</div>
            <div class="tab">Files</div>
            <div class="tab">Settings</div>
        </div>
        <div class="content-container">
            <div class="content active">
                <h3>Clients</h3>
                <p>This is the clients tab</p>
                <form id="clForm">
                    <label for="name">Name</label><br>
                    <input type="text" id="name" name="name" required><br>
                    <label for="pnum">Phone Number</label><br>
                    <input type="text" id="pnum" name="pnum" required><br>
                    <label for="age">Age</label><br>
                    <input type="text" id="age" name="age" required><br>
                    <!-- 移除inline onclick,通过事件监听绑定逻辑 -->
                    <button id="clBtn">Submit</button>
                </form>
                <section class="wrapper-main">
                    <table id="clientTable">
                        <thead>
                            <tr>
                                <th>Name</th>
                                <th>PhoneNumber</th>
                                <th>Age</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr>
                                <td>ClientName</td>
                                <td>PhoneNumber</td>
                                <td>ClientAge</td>
                            </tr>
                            <tr>
                                <td>ClientName</td>
                                <td>PhoneNumber</td>
                                <td>ClientAge</td>
                            </tr>
                        </tbody>
                    </table>
                </section>
            </div>
            <div class="content">
                <h3>Files</h3>
                <p>This is the files tab, upload files here!</p>
            </div>
            <div class="content">
                <h3>Settings</h3>
                <p>This is the settings tab</p>
            </div>
        </div>
    </div>
    <script src="renderer.js"></script>
</body>
</html>

额外注意事项

如果你的Electron应用未开启nodeIntegration(默认出于安全考虑关闭),渲染进程无法直接使用fs模块。此时需要通过ipcRenderer与主进程通信,由主进程完成文件读写:

// 主进程main.js示例
const { app, BrowserWindow, ipcMain, fs, path } = require('electron');

ipcMain.handle('save-client-data', async (event, clientData) => {
    const dataPath = path.join(app.getPath('userData'), 'table-data.json');
    let clients = [];
    try {
        const existingData = fs.readFileSync(dataPath, 'utf8');
        clients = JSON.parse(existingData);
    } catch (err) {}
    clients.push(clientData);
    fs.writeFileSync(dataPath, JSON.stringify(clients, null, 2));
    return true;
});

// 渲染进程中替换保存逻辑
const { ipcRenderer } = require('electron');
await ipcRenderer.invoke('save-client-data', { name, pnum, age });

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 18:25:04