如何在 JavaScript 中动态设置商品金额
支付小周
结论
为每个商品的操作按钮添加 data-price 属性,用来保存原始价格。用户点击按钮后,通过 dataset.price 或 jQuery 的 .data('price') 读取价格,再将其传给 openKkiapayWidget。
不要从页面显示的 XOF 50,000 中提取金额。货币符号和千位分隔符会让解析变得更麻烦。
实现方式
生成商品按钮时,一并写入商品价格:
<?php
$price = (int) $row['price'];
?>
<button
type="button"
class="pay-button"
data-price="<?= $price ?>"
>
<?= htmlspecialchars($row['action'], ENT_QUOTES, 'UTF-8') ?>
</button>
<span>XOF <?= number_format($price) ?></span>
data-price 保存未格式化的数值,例如 50000。只有页面展示价格时,才使用 number_format() 将其格式化为 50,000。
接着监听按钮的点击事件:
document.addEventListener("click", function (event) {
const button = event.target.closest(".pay-button");
if (!button) {
return;
}
const price = Number(button.dataset.price);
if (!Number.isFinite(price) || price <= 0) {
console.error("商品金额无效");
return;
}
openKkiapayWidget({
amount: price,
position: "center",
callback: "",
theme: "red",
key: "YOUR_PUBLIC_KEY"
});
});
如果支付网关要求 amount 使用字符串,可以写成:
amount: String(price)
实际需要哪种类型,应以当前支付网关的接口文档为准。
使用 jQuery 的写法
如果项目已经引入 jQuery,可以这样写:
$(document).on("click", ".pay-button", function () {
const price = Number($(this).data("price"));
if (!Number.isFinite(price) || price <= 0) {
console.error("商品金额无效");
return;
}
openKkiapayWidget({
amount: price,
position: "center",
callback: "",
theme: "red",
key: "YOUR_PUBLIC_KEY"
});
});
原来的代码无法正常工作,问题出在这里:
$(this).amount("price");
amount() 不是 jQuery 读取自定义属性的方法。要读取 data-price,应使用:
$(this).data("price");
也可以直接读取属性:
$(this).attr("data-price");
更安全的做法
用户可以修改前端传入的金额,所以最终扣款金额不能只根据 data-price 决定。更可靠的流程是让按钮只保存商品 ID。后端收到商品 ID 后,从数据库查询真实价格,再创建或验证支付交易。
<button
type="button"
class="pay-button"
data-product-id="<?= (int) $row['id'] ?>"
>
<?= htmlspecialchars($row['action'], ENT_QUOTES, 'UTF-8') ?>
</button>
前端把商品 ID 发送给后端:
document.addEventListener("click", async function (event) {
const button = event.target.closest(".pay-button");
if (!button) {
return;
}
const response = await fetch("/create-payment.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
productId: button.dataset.productId
})
});
if (!response.ok) {
console.error("无法创建支付交易");
return;
}
const payment = await response.json();
openKkiapayWidget({
amount: payment.amount,
position: "center",
callback: payment.callback,
theme: "red",
key: payment.publicKey
});
});
后端必须自行查询并校验商品价格,不能把浏览器直接提交的金额当作最终价格。支付完成后,服务端还需要验证支付状态和实际到账金额,然后再更新订单状态。
备注:内容仅供参考。
