
本文介绍如何使用原生 javascript 和 php 实现:页面加载时渲染含输入框的首行表格,用户输入条形码后,通过 ajax 异步查询数据库并填充对应商品信息,同时自动追加下一行空白输入行。全程无需 jquery,代码简洁可扩展。
要实现“逐行添加 + 条形码驱动数据填充”的交互式表格,核心在于三步协同:HTML 结构初始化 → 用户输入触发 AJAX 请求 → 后端响应后更新当前行 + 动态插入新行。下面以专业、可落地的方式逐步说明。
✅ 1. 前端 HTML 与初始结构
确保表格拥有唯一 ID(如 id="products"),首行使用 <input> 绑定 onchange 事件,并为后续动态行预留语义化 ID(如 product1、amount1):
<table id="products" class="s-table">
<thead>
<tr>
<th style="text-align: center;">barcode</th>
<th style="text-align: center;">product</th>
<th style="text-align: center;">amount</th>
<th style="text-align: center;">price</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center;">
<input type="text" placeholder="Enter barcode" onchange="onBarcodeChange(1)">
</td>
<td id="product1" style="text-align: center;"></td>
<td id="amount1" style="text-align: center;"></td>
<td id="price1" style="text-align: center;"></td>
</tr>
</tbody>
</table>⚠️ 注意:onchange 在用户失焦时触发(更稳妥);若需实时响应,可用 oninput + 防抖,但需自行处理重复请求。
✅ 2. 原生 JavaScript 核心逻辑(无 jQuery)
以下函数构成闭环流程:
- onBarcodeChange(id):接收行序号,发起 AJAX 请求,填充本行数据,并调用 addTableRow() 创建下一行;
- addTableRow(id):动态创建新 <tr>,含带 onchange 的输入框及空单元格;
- 使用 fetch() 替代过时的 XMLHttpRequest,更现代、简洁。
async function onBarcodeChange(id) {
const input = document.querySelector(`#barcode${id} input`) ||
document.querySelector(`tr:nth-child(${id}) td:first-child input`);
const barcode = input?.value.trim();
if (!barcode) return;
try {
// ? 发起 AJAX 请求(PHP 后端接口)
const response = await fetch('get_product.php', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `barcode=${encodeURIComponent(barcode)}`
});
if (!response.ok) throw new Error('Network response was not ok');
const data = await response.json();
// ✅ 填充当前行(根据 ID 定位)
document.getElementById(`product${id}`).textContent = data.product || '-';
document.getElementById(`amount${id}`).textContent = data.amount || '0';
document.getElementById(`price${id}`).textContent = `${data.price || '0'} $`;
// ➕ 追加下一行(ID 自增)
addTableRow(id + 1);
} catch (err) {
alert(`Error loading product: ${err.message}`);
console.error(err);
}
}
function addTableRow(id) {
const row = document.createElement('tr');
// 第一列:带事件的输入框
const barcodeCell = document.createElement('td');
barcodeCell.style.textAlign = 'center';
const input = document.createElement('input');
input.type = 'text';
input.placeholder = 'Enter barcode';
input.id = `barcode${id}`;
input.onchange = () => onBarcodeChange(id);
barcodeCell.appendChild(input);
// 其余三列:空单元格(带 ID 便于后续填充)
const cellNames = ['product', 'amount', 'price'];
const otherCells = cellNames.map(name => {
const td = document.createElement('td');
td.id = `${name}${id}`;
td.style.textAlign = 'center';
return td;
});
// 拼接整行
[barcodeCell, ...otherCells].forEach(td => row.appendChild(td));
document.getElementById('products').querySelector('tbody').appendChild(row);
input.focus(); // 自动聚焦新输入框,提升体验
}✅ 3. PHP 后端接口(get_product.php)
该文件接收条形码,查询 MySQL 并返回 JSON:
<?php
header('Content-Type: application/json; charset=utf-8');
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['barcode'])) {
http_response_code(400);
echo json_encode(['error' => 'Missing barcode']);
exit;
}
$barcode = trim($_POST['barcode']);
// ✅ 使用 PDO(推荐)或 mysqli —— 此处以 PDO 为例
try {
$pdo = new PDO("mysql:host=localhost;dbname=your_db", "username", "password");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare("SELECT product_name, amount, price FROM products WHERE barcode = ?");
$stmt->execute([$barcode]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($row) {
echo json_encode([
'product' => htmlspecialchars($row['product_name']),
'amount' => (int)$row['amount'],
'price' => (float)$row['price']
]);
} else {
echo json_encode(['product' => 'Not found', 'amount' => 0, 'price' => 0]);
}
} catch (PDOException $e) {
error_log('DB Error: ' . $e->getMessage());
http_response_code(500);
echo json_encode(['error' => 'Database error']);
}
?>✅ 安全提示:务必使用预处理语句防止 SQL 注入;输出前用 htmlspecialchars() 防 XSS。
✅ 4. 补充建议与最佳实践
- 用户体验优化:在 onBarcodeChange 开始时禁用输入框、显示 loading 文本,响应后恢复;
- 错误处理强化:对空结果、网络超时、HTTP 错误码做分层提示;
- 键盘支持:监听 Enter 键提交(input.addEventListener('keypress', e => e.key === 'Enter' && e.target.dispatchEvent(new Event('change'))));
- 性能考虑:若单页行数较多(>50),建议虚拟滚动或分页,避免 DOM 过载。
至此,你已拥有一套轻量、安全、可维护的“扫码即填表”解决方案——完全基于原生技术栈,零第三方依赖,可直接集成到现有 PHP 项目中。










