在 Vue.js 组件中放置 PayPal 按钮

Posted

技术标签:

【中文标题】在 Vue.js 组件中放置 PayPal 按钮【英文标题】:Placing PayPal buttons inside Vue.js component 【发布时间】:2021-02-26 07:50:45 【问题描述】:

我正在尝试在我的 Vue.js 组件中放置 PayPal 订单按钮。

我正在关注official documentation,它基本上说要做三件事:

    导入 PayPal SDK 脚本 定义将呈现按钮的<div> 元素 添加一些javascript tode来配置回调并使用变量paypal呈现按钮

这是我在纯 html 文件中执行此操作时的外观:

<!-- 1 -->

<script src="https://www.paypal.com/sdk/js?&client-id=xxx"></script>

<!-- 2 -->

<div id="paypal-button-container"></div>

<!-- 3 -->

<script>
  paypal.Buttons(
    createOrder: function (data, actions) 
      return fetch('http://localhost:8081/api/v1/pay-pal/create-order', 
        method: 'POST'
      ).then(function(res) 
        return res.json();
      ).then(function(data) 
        return data.id;
      );
    ,
    onApprove: function (data, actions) 
      return fetch('http://localhost:8081/api/v1/pay-pal/capture-order/' + data.orderID, 
        method: 'POST'
      ).then(function(res) 
        if (!res.ok) 
          alert('Something went wrong');
        
      );
    
  ).render('#paypal-button-container');
</script>

上面的代码可以找到。我的问题是如何在 Vue.js 组件中执行此操作。

对于第 1 步,我使用了这样的 mounted() 钩子:

mounted() 
    let payPalSdk = document.createElement('script')
    payPalSdk.setAttribute('src', 'https://www.paypal.com/sdk/js?&client-id=xxx')
    document.head.appendChild(payPalSdk)

第 2 步很简单,我只是在模板中添加了 div 元素。

但是我应该把 javascript 代码放在哪里来执行第 3 步?

我尝试将它放在一个外部 js 文件中,并在 mounted() 方法中加载它,如下所示:

mounted() 
    let payPalSdk = document.createElement('script')
    payPalSdk.setAttribute('src', 'https://www.paypal.com/sdk/js?&client-id=xxx')
    document.head.appendChild(payPalSdk)

    let payPalScript = document.createElement('script')
    payPalScript.setAttribute('src', '/js/paypal.js')
    document.head.appendChild(payPalScript)

paypal.js:

  paypal.Buttons(
    createOrder: function (data, actions) 
      return fetch('http://localhost:8081/api/v1/pay-pal/create-order', 
        method: 'POST'
      ).then(function(res) 
        return res.json();
      ).then(function(data) 
        return data.id;
      );
    ,
    onApprove: function (data, actions) 
      return fetch('http://localhost:8081/api/v1/pay-pal/capture-order/' + data.orderID, 
        method: 'POST'
      ).then(function(res) 
        if (!res.ok) 
          alert('Something went wrong');
        
      );
    
  ).render('#paypal-button-container');

按钮确实被渲染,但控制台显示以下错误:

buttons?style.layout…re&commit=true:1182 unhandled_error 
err: "Error: Invalid json: .↵    at XMLHttpRequest.<anon…rrency=USD&intent=capture&commit=true:1182:22901)", timestamp: "1605367583366", referer: "www.sandbox.paypal.com", sdkCorrelationID: "7d650f42fd450", sessionID: "09b33213cd_mtu6mjy6mja", …
buttonCorrelationID: "72135879fd67d"
buttonSessionID: "473d7ab57f_mtu6mjy6mja"
env: "sandbox"
err: "Error: Invalid json: .↵    at XMLHttpRequest.<anonymous> (https://www.sandbox.paypal.com/smart/buttons?style.layout=vertical&style.color=gold&style.shape=rect&style.tagline=false&components.0=buttons&locale.country=US&locale.lang=en&sdkMeta=eyJ1cmwiOiJodHRwczovL3d3dy5wYXlwYWwuY29tL3Nkay9qcz8mY2xpZW50LWlkPUFUX1hyMUl3ekZpM2ItRmhFd0RMQ0VndEM2Y2F4MHgwaWR1VF9yeEprQUhycFRlUXpkbHZRRDhKWFUxZmlNQ01vclN3T1hSWWU1eVVPaENBIiwiYXR0cnMiOnsiZGF0YS11aWQiOiJlOGQyMGY4MzBlX210dTZtank2bWphIn19&clientID=xxx&sessionID=09b33213cd_mtu6mjy6mja&buttonSessionID=473d7ab57f_mtu6mjy6mja&enableBNPL=true&env=sandbox&fundingEligibility=eyJwYXlwYWwiOnsiZWxpZ2libGUiOnRydWUsInZhdWx0YWJsZSI6dHJ1ZX0sInBheWxhdGVyIjp7ImVsaWdpYmxlIjpmYWxzZSwicHJvZHVjdHMiOnsiZmxleCI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJwYXlJbjQiOnsiZWxpZ2libGUiOmZhbHNlfX19LCJjYXJkIjp7ImVsaWdpYmxlIjp0cnVlLCJicmFuZGVkIjp0cnVlLCJpbnN0YWxsbWVudHMiOmZhbHNlLCJ2ZW5kb3JzIjp7InZpc2EiOnsiZWxpZ2libGUiOnRydWUsInZhdWx0YWJsZSI6dHJ1ZX0sIm1hc3RlcmNhcmQiOnsiZWxpZ2libGUiOnRydWUsInZhdWx0YWJsZSI6dHJ1ZX0sImFtZXgiOnsiZWxpZ2libGUiOnRydWUsInZhdWx0YWJsZSI6dHJ1ZX0sImRpc2NvdmVyIjp7ImVsaWdpYmxlIjpmYWxzZSwidmF1bHRhYmxlIjp0cnVlfSwiaGlwZXIiOnsiZWxpZ2libGUiOmZhbHNlLCJ2YXVsdGFibGUiOmZhbHNlfSwiZWxvIjp7ImVsaWdpYmxlIjpmYWxzZSwidmF1bHRhYmxlIjp0cnVlfSwiamNiIjp7ImVsaWdpYmxlIjpmYWxzZSwidmF1bHRhYmxlIjp0cnVlfX19LCJ2ZW5tbyI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJpdGF1Ijp7ImVsaWdpYmxlIjpmYWxzZX0sImNyZWRpdCI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJzZXBhIjp7ImVsaWdpYmxlIjpmYWxzZX0sImlkZWFsIjp7ImVsaWdpYmxlIjpmYWxzZX0sImJhbmNvbnRhY3QiOnsiZWxpZ2libGUiOmZhbHNlfSwiZ2lyb3BheSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJlcHMiOnsiZWxpZ2libGUiOmZhbHNlfSwic29mb3J0Ijp7ImVsaWdpYmxlIjpmYWxzZX0sIm15YmFuayI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJwMjQiOnsiZWxpZ2libGUiOmZhbHNlfSwiemltcGxlciI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJ3ZWNoYXRwYXkiOnsiZWxpZ2libGUiOmZhbHNlfSwicGF5dSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJibGlrIjp7ImVsaWdpYmxlIjpmYWxzZX0sInRydXN0bHkiOnsiZWxpZ2libGUiOmZhbHNlfSwib3h4byI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJtYXhpbWEiOnsiZWxpZ2libGUiOmZhbHNlfSwiYm9sZXRvIjp7ImVsaWdpYmxlIjpmYWxzZX0sIm1lcmNhZG9wYWdvIjp7ImVsaWdpYmxlIjpmYWxzZX19&platform=desktop&flow=purchase&currency=USD&intent=capture&commit=true:1182:22901)"
referer: "www.sandbox.paypal.com"
sdkCorrelationID: "7d650f42fd450"
sessionID: "09b33213cd_mtu6mjy6mja"
timestamp: "1605367583366"
__proto__: Object
y   @   buttons?style.layout…re&commit=true:1182
S   @   buttons?style.layout…re&commit=true:1182
error   @   buttons?style.layout…re&commit=true:1182
(anonymous) @   buttons?style.layout…re&commit=true:1182
(anonymous) @   buttons?style.layout…re&commit=true:1182
(anonymous) @   buttons?style.layout…re&commit=true:1182
setTimeout (async)      
n.reject    @   buttons?style.layout…re&commit=true:1182
(anonymous) @   buttons?style.layout…re&commit=true:1182
n.dispatch  @   buttons?style.layout…re&commit=true:1182
n.reject    @   buttons?style.layout…re&commit=true:1182
n.dispatch  @   buttons?style.layout…re&commit=true:1182
n.reject    @   buttons?style.layout…re&commit=true:1182
n.dispatch  @   buttons?style.layout…re&commit=true:1182
n.reject    @   buttons?style.layout…re&commit=true:1182
(anonymous) @   buttons?style.layout…re&commit=true:1182
(anonymous) @   buttons?style.layout…re&commit=true:1182
load (async)        
(anonymous) @   buttons?style.layout…re&commit=true:1182
e   @   buttons?style.layout…re&commit=true:1182
ke  @   buttons?style.layout…re&commit=true:1182
Oe  @   buttons?style.layout…re&commit=true:1182
(anonymous) @   buttons?style.layout…re&commit=true:1182
e.try   @   buttons?style.layout…re&commit=true:1182
w   @   buttons?style.layout…re&commit=true:1182
e.try   @   buttons?style.layout…re&commit=true:1182
(anonymous) @   buttons?style.layout…re&commit=true:1182
setTimeout (async)      
w::promiseDebounced @   buttons?style.layout…re&commit=true:1182
G.then.intent   @   buttons?style.layout…re&commit=true:1182
(anonymous) @   buttons?style.layout…re&commit=true:1182
n.dispatch  @   buttons?style.layout…re&commit=true:1182
n.resolve   @   buttons?style.layout…re&commit=true:1182
n.dispatch  @   buttons?style.layout…re&commit=true:1182
n.resolve   @   buttons?style.layout…re&commit=true:1182
n.dispatch  @   buttons?style.layout…re&commit=true:1182
n.resolve   @   buttons?style.layout…re&commit=true:1182
(anonymous) @   buttons?style.layout…re&commit=true:1182
n.dispatch  @   buttons?style.layout…re&commit=true:1182
n.resolve   @   buttons?style.layout…re&commit=true:1182
n.dispatch  @   buttons?style.layout…re&commit=true:1182
n.resolve   @   buttons?style.layout…re&commit=true:1182
n.dispatch  @   buttons?style.layout…re&commit=true:1182
n.resolve   @   buttons?style.layout…re&commit=true:1182
(anonymous) @   buttons?style.layout…re&commit=true:1182
(anonymous) @   buttons?style.layout…re&commit=true:1182
setInterval (async)     
(anonymous) @   buttons?style.layout…re&commit=true:1182
e   @   buttons?style.layout…re&commit=true:1182
(anonymous) @   buttons?style.layout…re&commit=true:1182
anonymous::memoized @   buttons?style.layout…re&commit=true:1182
G.style @   buttons?style.layout…re&commit=true:1182
ht  @   buttons?style.layout…re&commit=true:1182
(anonymous) @   buttons?style.layout…re&commit=true:1183

我也尝试将代码放入 mounted() 钩子中,但这不起作用,因为变量 paypal 在那里未定义。

【问题讨论】:

@tao 该 URL 实际上返回 HTML,而不是 JSON。这不是问题,因为当我在工作示例中尝试它时它返回相同的 HTML。 【参考方案1】:

从mounted() 试试这个,看看是否在加载PayPal JS 后使用回调或客户端createOrder/onApprove 产生影响

function loadAsync(url, callback) 
  var s = document.createElement('script');
  s.setAttribute('src', url); s.onload = callback;
  document.head.insertBefore(s, document.head.firstElementChild);


loadAsync('https://www.paypal.com/sdk/js?client-id=sb&currency=USD', function() 
  paypal.Buttons(

    // Set up the transaction
    createOrder: function(data, actions) 
        return actions.order.create(
            purchase_units: [
                amount: 
                    value: '0.01'
                
            ]
        );
    ,

    // Finalize the transaction
    onApprove: function(data, actions) 
        return actions.order.capture().then(function(details) 
            // Show a success message to the buyer
            alert('Transaction completed by ' + details.payer.name.given_name);
        );
    

  ).render('#paypal-button-container');
);

至于实际的客户端批准代码继续与您的服务器后端配对,我推荐https://developer.paypal.com/demo/checkout/#/pattern/server的错误处理

【讨论】:

谢谢,我试过这种方式,但我得到了完全相同的错误。 你的 vue 环境中的某些东西正在干扰或阻止 XHR 请求。检查网络选项卡和跨站点标题。 在网络选项卡中对 paypal.com 的所有调用都返回 200。“检查跨站点标题”是什么意思? 如果是200,那么响应体不是JSON怎么办? 我没有看到任何返回 JSON 的请求。甚至在工作示例中也没有。

以上是关于在 Vue.js 组件中放置 PayPal 按钮的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Vuex 商店的 Vue.js 组件中设置动态样式

从 PayPal 检索 PayKey 时出现错误 580022(无效的 AccountID)。应该在接收者的 AccountID 中放置啥以及在哪里可以找到该信息?

Vuetify.js:如何在左右两侧的 v-card 中放置按钮操作?

vue.js怎样解决按钮多次点击重复提交

如何在我的 ag-grid 单元格中放置一个 react jsx 组件

java怎么实现在一个类中放置监听器,而在另一个类中事件呢?