PAYATHON 2026

如何在 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
    });
});

后端必须自行查询并校验商品价格,不能把浏览器直接提交的金额当作最终价格。支付完成后,服务端还需要验证支付状态和实际到账金额,然后再更新订单状态。

备注:内容仅供参考。