订单表格应将置于外层,每行商品用,数量输入框用并命名如name="items0",小计通过监听input事件实时计算,提交前校验数量有效性。

订单表格结构用 <table> 搭建,但别嵌套表单<p>HTML 表格本身不处理数据,只是展示容器。把 <code><form></form> 放在 <table> 外层,而不是每个 <code><tr> 里套一个表单——否则提交时只能拿到最后一行的值。每一行商品用 <code><tr>,商品名、单价、数量输入框、小计用 <code><td> 拆开,数量用 <code><input type="number">,加 min="1" 和 step="1" 防负数和小数。
name 属性必须带唯一标识,否则后端收不到多行数据
name 属性必须带唯一标识,否则后端收不到多行数据如果所有数量框都写 name="quantity",PHP 或 Node.js 默认只取最后一个值。正确做法是用数组式命名:name="items[0][quantity]"、name="items[1][quantity]",或语义化命名如 name="quantity[prod-101]"。对应商品 ID 或索引,方便后端遍历解析。别依赖 id——它只用于 JS 或 CSS,不参与表单提交。
小计实时计算得靠 JS,input 事件比 change 更及时
用户还没离开输入框就该更新小计,所以监听 input 事件,不是 change。每行绑定独立逻辑:取当前行的单价单元格文本(parseFloat(td[1].textContent))、取数量输入框的 valueAsNumber,相乘后写进对应的小计 <td>。注意空值和非数字要判空,否则算出 <code>NaN。
document.querySelectorAll('input[name^="quantity"]').forEach(inp => {
inp.addEventListener('input', function() {
const row = this.closest('tr');
const price = parseFloat(row.cells[1].textContent) || 0;
const qty = this.valueAsNumber || 0;
row.cells[3].textContent = (price * qty).toFixed(2);
});
});
提交前校验数量是否为空或为 0,避免后端白忙活
用户可能清空输入框或输 0,但 type="number" 清空后 valueAsNumber 是 NaN,不是 0。校验时用 !inp.valueAsNumber && inp.value !== '' 判断无效输入。发现异常就 inp.focus() 并提示,event.preventDefault() 拦住提交。别只靠前端校验,后端仍要二次检查,但前端拦截能立刻反馈。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
容易漏掉的是 disabled 输入框——比如库存为 0 时禁用,但若没同步设 name 属性,它就不会随表单提交,后端就收不到这条记录的意图。需要保留 name,仅用 disabled 控制编辑,再靠 hidden input 传状态。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










