PaymentRequest API 是一种跨浏览器的标准 API,主要的目的是以浏览器充当中介,尽可能标准化支付通信的流程。 ????整个流程主要是创建 PaymentRequest,将购买货物的详细信息传递给浏览器,在 UI 层面显示支付的 UI,用户填入支付信息或从缓存中一键填充并确认支付。他的最大的优势是信用卡、收货地址等支付信息都统一存储在浏览器,如果网站都能够使用该 API,那么就不再需要重复填写支付信息。⚠️ 使用 PaymentRequest 非常简单,但由于兼容性问题,目前不要在生产环境中使用,API 层面亦会有可能改动。创建 PaymentRequest 实例第一步是通过调用 PaymentRequest 构造函数创建一个 PaymentRequest 对象构造函数需要三个参数分别是 methodData、details 和可选的 optionsmethodData 支付方式首先需要设定支付方式,传入卖家支持的支付手段,如 visa 或 mastercard 等信用卡或其他方式:methodData 是一个数组,数组中每一项应为一个对象,对象内包含两个属性:supportedMethods 付款方式识别符data 额外信息supportedNetworks 支付网络supportedMethods 需要填写 付款方式识别符,一般填写 basic-card,也可填写 url 的识别符如:如果是 google pay url 付款识别符,那么调用的时候长这样:这里以 basic-card 为例,那么 data 属性则需要填写一些额外的信息,如果是 basic-card 方式,那么还可以选择配置 supportedNetworks,这个选项指定了 card networkscard networks 是一个数组,如支持 visa、mastercard 等[‘visa’, ‘mastercard’, ‘amex’, ‘jcb’, ‘diners’, ‘discover’, ‘mir’, ‘unionpay’]什么是 card networks 见这篇文章:https://www.cardinalcommerce….根据规范,我们编写以下代码 ????const methodData = [{ supportedMethods: ‘basic-card’, data: { supportedNetworks: [‘visa’, ‘mastercard’, ‘amex’, ‘jcb’, ‘diners’, ‘discover’, ‘mir’, ‘unionpay’] }}]在调用的时候长这样:另外,Apple Pay 也支持该特性,详细见文档:https://webkit.org/blog/8182/…details 交易详情details 保存的是交易详情,主要有以下字段:total 需要支付的总额id 交易 ID,如果不填写浏览器自动生成displayItems 主要是一些货品信息、税费、运费等详细清单shippingOptions 则是运输相关的选项,有事件监听如果不能送达,则应在 UI 层面给用户提示modifier 主要是针对用户付款方式,修改交易详情,比方说针对某种支付手段给予优惠,展示不同金额等additionalDisplayItems 额外需要展示的新增订单项目data 额外信息total 修改后的总价total这一字段需要填写支付总额,API 不会自动计算,需要计算后填入 total 字段需要满足 PaymentItem 规范也就是说至少需要一个 label 字符串和一个 PaymentCurrencyAmount 金额,另外还有一个可选项 pending 用来表示是否为最终金额,默认为 false:PaymentCurrencyAmount 则需要两个属性,一个是 currency 一个是 value,两个都是字符串:const details = { total: { label: ‘合计总金额 ???? ‘, amount: { currency: ‘CNY’, value: ‘100.00’ } }}增加 details 对象,编写代码如上所示效果如下:idid 则代表了交易 ID,可以自定义,字符串格式:const details = { id: ‘Order-Funny-ID-000-001’, total: {displayItems订单详情,每个单个条目最终是否展示取决于浏览器。这是一个数组,数组内每一个对象都是一个 PaymentItem,因此数组内每一项的规范参照 total:const details = { id: ‘Order-Funny-ID-000-001’, displayItems: [{ label: ‘西瓜 ????’, amount: { currency: ‘CNY’, value: ‘20.00’ } }, { label: ‘草莓 ????’, amount: { currency: ‘CNY’, value: ‘90.00’ } }, { label: ‘VIP 会员 ????’, amount: { currency: ‘CNY’, value: ‘-10.00’ }, pending: true }], total: { label: ‘合计总金额 ???? ‘, amount: { currency: ‘CNY’, value: ‘100.00’ } }}上面代码执行效果长这样:shippingOptions根据规范 shippingOptions 应该有三个必选参数,id、label、amount(同样,amount 必须符合 PaymentCurrencyAmount),selected 默认为 false,是可选参数:const details = { id: ‘Order-Funny-ID-000-001’, displayItems: [{ }], total: { }, shippingOptions: [{ id: ‘标准快递’, label: ‘???? 免费普通快递 1 天全国范围内’, amount: { currency: ‘CNY’, value: ‘0.00’ }, selected: true }, { id: ‘东风快递’, label: ‘???? 超快速递 3 小时全球范围内’, amount: { currency: ‘CNY’, value: ‘100.00’ } }]}const options = { requestShipping: true // 别忘记这里需要设置为 true}let request = new PaymentRequest( methodData, // 支付方式 details, // 交易信息 options // 其他额外信息)按上述规范配置 shippingOptions,并监听配送选项改变或地址改变动态调整收费价格标准// 监听配送选项改变,动态修改收费标准request.onshippingoptionchange = function (e) { console.log(‘快递选项改变,重新计算价格’) e.updateWith(Promise.resolve(updateDetail(details, request.shippingOption))) // 接收 promise}// 监听地址选项改变,动态修改收费标准request.onshippingaddresschange = function (e) { console.log(‘地址选项改变,重新计算价格’) e.updateWith(Promise.resolve(updateDetail(details, request.shippingOption))) // 接收 promise}function updateDetail(details, shippingOpts) { console.log({ details, shippingOpts }) // shippingOpts 代表选择的快递 id // fetch 后台数据 // 各种判断 // 修改 details 最后 return 出去 // if (shippingOpts) {} else {} // 这里仅作演示没修改数据 return details}modifier用于修改账单,这里以 visa 卡为例,使用此类型信用卡会在账单中增加一条 additionalDisplayItems,并通过 total 修改账单总额modifier 需要一个 supportedMethods 为必选参数:modifiers: [ { additionalDisplayItems: [{ label: ‘visa 手续费’, amount: { currency: ‘CNY’, value: ‘10.00’ } }], supportedMethods: “basic-card”, total: { label: “Total due”, amount: { currency: “USD”, value: “110.00” }, }, data: { supportedNetworks: [‘visa’], }, },]效果如下:options主要有六个参数可供配置,分别是 requestPayerName、requestPayerEmail、requestPayerPhone、requestShipping、requestBillingAddress、shippingType,前五项默认为 false,最后一项可设置为 shipping、delivery、pickup,三者根据语境选择合适的 UI 层面对“快递”的描述,这三个单词在中国大陆分别代表送货、递送和取货request 实例的属性和方法上文提到的 shippingaddresschange 和 shippingoptionchange 就是该实例的两个事件,除此之外还有 paymentmethodchange 和 merchantvalidation。除事件之外,实例的四个属性分别是 id、shippingAddress、shippingOption、shippingType 可以访问到这个支付请求的相关配置。该实例的三个方法比较重要,用来鉴定是否能够发起支付的 canMakePayment、调起 UI 支付界面的 show 以及放弃支付的 abort。canMakePayment检测是否支持此种支付方式,在使用之前必须先要判断浏览器是否支持 canMakePayment 本身:if (request.canMakePayment) {} else {+ ;(() => { console.log(‘浏览器不支持 canMakePayment 特性’) })()}然后调用方法检测支付:if (request.canMakePayment) {+ request.canMakePayment().then(res => {+ }).catch(console.error)} else { ; (() => { console.log(‘浏览器不支持 canMakePayment 特性’) })()}根据检测结果判断是否进一步调用 show,发起支付:if (request.canMakePayment) { request.canMakePayment().then(res => {+ if (res) {+ request.show() // true 如果支持+ } else {+ console.log(‘未能发起支付’)+ } }).catch(console.error)} else { ; (() => { console.log(‘浏览器不支持 canMakePayment 特性’) })()}show最终获取支付成功的 response 是通过 show 方法返回的,最后确认无误后,调用 response 的 complete 方法,并传入 success、fail 或 unknow 字段来结束支付:if (request.canMakePayment) { request.canMakePayment().then(res => { if (res) {+ request.show().then(response => {+ console.log(response)+ setTimeout(() => { // 模拟发送支付信息到服务端,并调用 response 的 complete 方法完成支付+ response.complete()+ }, 2000) }) } else { console.log(‘未能发起支付’) } }).catch(console.error)} else { ; (() => { console.log(‘浏览器不支持 canMakePayment 特性’) })()}此外 response 还有 retry 方法,可以在遇到支付 response 出现错误的时候重新发起支付关于 response 的属性和方法见如下截图:附上用于测试的信用卡卡号最后附上用于测试的信用卡卡号,日期随便填,CVC 随便填Test Credit Card Account Numbers http://www.blogjava.net/sealy…最后代码在此:https://jsfiddle.net/aL5gczm3/