
本文介绍如何使用 javascript(配合 jquery)在动态表格中智能处理重复商品:当用户选择已存在的商品时,不新增行,而是将对应行的 quantity 单元格值加 1,从而实现「去重+累加」的 pos 系统核心逻辑。
本文介绍如何使用 javascript(配合 jquery)在动态表格中智能处理重复商品:当用户选择已存在的商品时,不新增行,而是将对应行的 quantity 单元格值加 1,从而实现「去重+累加」的 pos 系统核心逻辑。
在开发收银系统或购物车功能时,频繁扫描同一商品(如两次扫描“Result 1”)若直接插入新行,会导致数据冗余、统计困难且界面混乱。理想行为应是:首次添加 → 新建一行,数量为 1;再次添加相同商品 → 定位已有行,将其 quantity 输入框的值递增 1。
以下是一个完整、可直接运行的解决方案,基于 jQuery 实现,无需后端依赖:
✅ 核心逻辑说明
- 每次点击「Add stock transfer」按钮,动态追加一个含搜索框和数量输入框的新行(初始 quantity 设为
1); - 用户点击搜索结果(如
<p>Result 1</p>)后,脚本遍历<tbody> 中所有已有行;<li>若发现某行的 <code>stock输入框值与当前选中项完全匹配,则解析其qty值,执行parseInt(currentQty) + 1并更新; - 若未匹配,则将当前选中值填入新行,并保留
qty=1; - 关键优化:匹配成功后,立即移除刚创建的空行(避免冗余 DOM),确保表格始终只含唯一商品项。
? 完整可运行代码示例
<!DOCTYPE html>
<html>
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<button class="btn btn-primary btnaddstockTransfer" type="button">
Add stock transfer
</button>
<div style="overflow-x:auto; margin-top: 1rem;">
<table id="stockTransfer" class="table table-bordered">
<thead>
<tr>
<th style="color:#0d6efd">Search Product (Name/Code)</th>
<th style="color:#0d6efd">Quantity</th>
</tr>
</thead>
<tbody>
<!-- 初始空行由 JS 动态管理 -->
</tbody>
</table>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
$(document).on('click', '.btnaddstockTransfer', function() {
// 动态生成新行(注意:始终 append 到 tbody,语义更规范)
const html = `
<tr>
<td>
<div class="search-box">
<input class="form-control is-warning stock"
type="text" name="stock[]" placeholder="Search by name or code">
<div class="result"></div>
</div>
</td>
<td>
<input class="form-control qty" type="number" name="qty[]" required min="1" value="1">
</td>
</tr>`;
$('#stockTransfer tbody').append(html);
});
// 实时搜索(仅演示,无真实请求)
$(document).on('input', '.search-box input[type="text"]', function() {
const inputVal = $(this).val().trim();
const $result = $(this).siblings('.result');
if (inputVal.length > 0) {
$result.html('<p>Result 1</p><p>Result 2</p><p>Result 3</p>');
} else {
$result.empty();
}
});
// 点击搜索结果项
$(document).on('click', '.result p', function() {
const selectedStock = $(this).text().trim();
const $tr = $(this).closest('tr'); // 新增行的 tr
const $qtyInput = $tr.find('.qty');
let itemExists = false;
// 遍历所有已有商品行(排除当前新行)
$('#stockTransfer tbody tr').not($tr).each(function() {
const existingStock = $(this).find('.stock').val()?.trim();
const $existingQty = $(this).find('.qty');
if (existingStock === selectedStock) {
const currentQty = parseInt($existingQty.val()) || 0;
$existingQty.val(currentQty + 1);
itemExists = true;
return false; // break loop
}
});
if (itemExists) {
$tr.remove(); // 移除重复添加的空行
} else {
$tr.find('.stock').val(selectedStock);
$qtyInput.val(1); // 显式设为 1(虽已默认,但更健壮)
}
$(this).parent('.result').empty();
});
});
</script>
</body>
</html>⚠️ 注意事项与最佳实践
-
严格相等判断:使用
===和.trim()避免因空格或大小写导致误判(如"Result 1 "≠"Result 1"); -
数值安全转换:
parseInt(...)后需|| 0防止NaN;推荐对qty使用type="number"并设置min="1"提升表单约束; -
DOM 性能:
.not($tr)排除当前新行,避免自匹配;遍历时用return false提前退出,提升效率; -
可扩展性建议:后续可引入商品 ID(而非仅名称)作为唯一键,支持同名不同规格商品;也可封装为独立函数(如
updateOrAddItem(name, delta=1))便于复用; -
无障碍友好:为搜索框添加
aria-label,结果列表使用<ul><li></ul>更符合语义化标准。
该方案简洁、鲁棒、即插即用,完美契合零售场景下「扫码即累加」的交互直觉,是构建专业级前端 POS 系统的关键一环。

















