edo1z blog

プログラミングなどに関するブログです

vue + stripe-elementのコンポーネントを自作した

vue-stripe-elementsを使っていて困ったこと

最初下記を使っていて、すごく使いやすかったのですが、複数ヶ所でstripe-elementを表示させようとするとエラーになってうまくできませんでした。

github.com

vue-stripe-elementsのissue

同じようなことで困ってる人がいるようで、issueみても解決してないみたいだったので、自作しました。

github.com

自作したやつ

ボタンが、vuetify仕様になっております。まだ、カード番号入力中に支払いボタンが一瞬アクティブになったりするし、ボタンクリック時にローディングまでのタイムラグが若干あったりと、改善点がありますが、上記問題は解決できました。

<template>
  <div>
    <div :class="stripeElementClass"></div>
    <div :class="errorClass">{{ errorMessage }}</div>
    <v-btn
      :color="btnColor"
      :large="btnSize === 'large'"
      class="stripe-element-btn"
      @click.prevent="createToken"
      :disabled="!complete"
      :loading="btnLoading"
    >
      <slot></slot>
    </v-btn>
  </div>
</template>

<script>
  export default {
    props: [
      'stripeKey', 'stripeOptions', 'btnColor',
      'btnSize', 'cardClass', 'errorClass',
      'btnLoading'
    ],
    data: () => ({
      stripe: null,
      stripeElement: null,
      token: null,
      complete: false,
      errorMessage: '',
      newCardClass: null,
    }),
    created() {
      this.stripe = Stripe(this.stripeKey)
      this.newCardClass = this.cardClass + this._randomString(20)
    },
    mounted() {
      this.createStripeElement()
    },
    computed: {
      stripeElementClass: function() {
        return [this.cardClass, this.newCardClass]
      }
    },
    methods: {
      async createToken() {
        try {
          if (!this.complete) return
          const result = await this.stripe.createToken(this.stripeElement)
          if (result.error) {
            this.errorMessage = result.error.message
          } else {
            this.$emit('token', result.token.id)
          }
        } catch (err) {
          this.errorMessage = err.message
        }
      },
      createStripeElement() {
        const elements = this.stripe.elements();
        this.stripeElement = elements.create('card', {style: this.stripeOptions, hidePostalCode: true});
        this.stripeElement.mount('.' + this.newCardClass)
        this.stripeElement.addEventListener('change', event => {
          if (event.error) {
            this.complete = false
            this.errorMessage = event.error.message
          } else {
            this.errorMessage = ''
            this.complete = true
          }
        })
      },
      _randomString(len) {
        const str = "abcdefghijklmnopqrstuvwxyz0123456789";
        let r = '';
        for (let i = 0; i < len; i++) {
          r += str[Math.floor(Math.random() * str.length)];
        }
        return r
      }
    }
  }
</script>