本文介绍如何将为多个输入框(如 50 行商品信息)逐个发起 ajax 请求的低效写法,重构为仅用一个通用事件监听 + 单次请求逻辑的高性能方案,显著减少 http 开销并提升可维护性。
在实际开发中,当表单包含大量动态行(例如 50+ 行采购/销售明细)时,若为每行 productCode 输入框单独绑定 change 事件并调用独立的 AJAX 函数(如 getDataFromServer1()、getDataFromServer2()…),不仅代码冗余、难以维护,还会造成严重的性能隐患:每输入一次就触发一次请求,极易引发并发阻塞、服务端压力激增,甚至触发浏览器同源请求限制。
✅ 正确做法是:统一事件委托 + 动态上下文识别 + 单一 AJAX 函数复用。
// ✅ 统一事件监听(支持未来动态追加行)
jQuery(document).on('change', '.product-code', function() {
const $this = jQuery(this);
const PID = $this.val().trim();
const itemId = $this.data('id'); // 获取当前行号
const nextItemId = itemId + 1;
if (PID && !isNaN(itemId)) {
getDataFromServer(PID, itemId);
// 自动聚焦下一行(边界需校验,如:if (nextItemId <= 50))
jQuery(`#productCode_${nextItemId}`).focus();
}
});
// ✅ 单一函数处理所有行
function getDataFromServer(PID, itemId) {
$.ajax({
type: "POST",
url: "response.php",
data: { pro_id: PID },
dataType: "json", // ⚠️ 推荐直接设为 json,避免手动 parse
success: function(res) {
if (res && res.pro_name !== undefined) {
$(`#productName_${itemId}`).val(res.pro_name);
$(`#productOnHand_${itemId}`).val(res.pro_quantity || 0);
$(`#price_${itemId}`).val(parseFloat(res.pro_price) || 0);
$(`#quantity_${itemId}`).val(1);
// 可选:触发本行小计计算
calculateRowTotal(itemId);
}
},
error: function(xhr) {
console.warn(`获取商品 ${PID} 数据失败:`, xhr.statusText);
alert("商品信息加载异常,请检查编号是否正确");
}
});
}
// 示例:行级小计计算(可根据需要扩展)
function calculateRowTotal(itemId) {
const qty = parseFloat($(document).find(`#quantity_${itemId}`).val()) || 0;
const price = parseFloat($(document).find(`#price_${itemId}`).val()) || 0;
$(`#total_${itemId}`).val((qty * price).toFixed(2));
}
ID === '') return;,并在 AJAX 发送前禁用当前输入框($this.prop('disabled', true)),成功后再启用; false, 'message' => '无效商品编号']);
exit;
}
// 查询数据库...
echo json_encode([
'success' => true,
'pro_name' => $row['name'],
'pro_quantity' => (int)$row['onhand'],
'pro_price' => (float)$row['price']
]);
?>通过以上重构,50 行表单从 50 个独立请求 → 1 个可复用函数 + 智能事件分发,代码量减少 80%+,维护成本大幅降低,同时为后续功能扩展(如实时校验、错误高亮、撤销操作)打下坚实基础。