无需jQuery:从表单生成表格行并保存至JSON(Electron环境)
问题描述
在Electron环境开发应用,尝试实现无jQuery功能:从表单获取用户输入生成新表格行,同时将数据保存到JSON文件避免页面刷新后丢失。目前存在两个核心问题:
- 新增的表格行瞬间消失
- 单元格内容显示为
[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_
相关产品推荐
相关产品推荐

