如何监听Stripe cardElement 的input 事件判断card 是否无效并禁用按钮?

How to listen to the input event of the Stripe cardElement to determine if card is invalid and disable the button?

当我的用户填写带有订单信息和客户详细信息的表单时,我禁用了提交按钮,直到我的验证得到满足。我使用的库是 express-validate。

我想做的是让按钮保持禁用状态,首先直到用户将信用卡信息输入到 Stripe 元素中,它实际上是一张有效的卡。 其次,提交后,再次禁用该按钮,这样用户就无法继续点击该按钮。当成功或成功或错误通知返回时,我将重定向。

到目前为止,我没有成功触发 cardElement.on() 方法,Stripe events. And this was the example of what I am trying to achieve,see client.js

这是我目前所拥有的...

Home.vue

<form
    id="order-info"
    class="form-container"
    @submit.prevent="createOrder"
  >
  ...

<div class="stripe-container">
        <div id="stripe-element-card" ref="card">
          <!-- Stripe.js injects the Card Element -->
        </div>
      </div>
      <p id="card-error" role="alert" />
      <p class="result-message hidden">
        Payment succeeded
      </p>
      <button
        v-if="toggleUserInfo"
        id="submit"
        class="stripe"
        :disabled="$v.$invalid" // this is based on current form validations
        type="submit"
        // I want to disable also until card is valid and then disable again 
        // after user clicks to prevent additional clicking until success/error returns
      >
        <div
          id="spinner"
          class="spinner"
          :class="{ hidden: !isLoading }"
        ></div>
        <span id="button-text" :class="{ hidden: isLoading }">Pay now</span>


<script>
async mounted() {
stripe = await loadStripe(process.env.VUE_APP_STRIPE_PK);
elements = stripe.elements();
card = elements.create("card", { style: style });
card.mount("#stripe-element-card");
 },

...

createOrder 方法

async createOrder(event) {
  console.log(event.target);
  this.loading(true);
  this.$v.$touch();
  if (!this.$v.$invalid) {

    // gather order and user details, superfluous code

    const cardElement = elements.getElement("card");

    const billingDetails = {
      name: user.name,
      address: {
        city: user.city,
        line1: user.street,
        state: "NY"
      },
      phone: user.phone
    };
    try {
      cardElement.on("change", event => {
        console.log("LOGGING THE CARD ELEMENT EVENT", event);
        // NOT SEEING ANYTHING HERE
        // disable button until valid card is inputted
      });
      ...

编辑

在下面实现 Pompey 的回答时,mounted() 中的侦听器,这就是 console.logs 在信用卡输入完成之前的样子...

需要注意的一件重要事情是,想要启用触发 createOrder 的按钮的 change 处理程序位于 createOrder 方法本身。我会将处理程序代码移动到卡元素安装在 Home.vue:

之后
card.mount("#stripe-element-card");
cardElement.on("change", event => {
  console.log("LOGGING THE CARD ELEMENT EVENT", event);
  if (event.complete) {
    // enable payment button
  } else if (event.error) {
    // show event.error.message to customer
  }
});

正如您从我上面的代码片段中看到的那样,event 参数有一个 complete 属性,当卡片元素的值为“格式良好且可能完整”[1],因此当它为真时,您可以启用您的按钮。检查 change 处理程序中的 event.error 也是值得的,如果存在,则向用户显示 event.error.message.

同样,要根据付款成功重定向客户或重新启用按钮,您可以使用 then 方法从 confirmCardPayment 获取指示成功或失败的响应[2] :

stripe.confirmCardPayment('{PAYMENT_INTENT_CLIENT_SECRET}', {
    ...
  })
  .then(function(result) {
    if(result.error)
    {
      // Display result.error.message and re-enable button to allow for more attempts
    }
    else
    {
      // React to successful payment
    }
  });

[1]https://stripe.com/docs/js/element/events/on_change?type=cardElement#element_on_change-handler-complete

[2]https://stripe.com/docs/js/payment_intents/confirm_card_payment