创建 Vue.js 无服务器结账表单:应用程序和结账组件

Avatar of Sarah Drasner
Sarah Drasner

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

这是四部分系列文章中的第三篇。在第一部分中,我们在 Azure 上设置了一个无服务器 Stripe 函数。第二部分介绍了如何在 Github 上托管该函数。本文将重点介绍如何将其连接为一个 Vue.js 应用程序。

文章系列

  1. 设置和测试
  2. Stripe 函数和托管
  3. 应用程序和结账组件(本文)
  4. 配置结账组件

Stripe 提供了许多构建结账表单的方法,最基本的方法是在页面上放置一个按钮,触发该按钮以弹出其自定义模态框。有一个 此组件的代码库和组件,但尽管它易于实现(这可能是最简单的方法),但我想要更多自定义,并希望结账流程成为页面和应用程序的一部分。这种方法不适合我的需求。

Stripe 元素

Stripe 还提供了一个称为 元素 的功能。元素允许您将 Stripe 的支付系统集成到您自己的结账表单中,并将其样式设置为与您自己的网站一致,从而获得连贯的体验。您不会感觉自己正在使用第三方插件。如果您更喜欢开箱即用的内容,他们确实有一些 预设样式示例

幸运的是,有一个非常不错的代码库,其中包含 Stripe 元素的 Vue 版本,名为 vue-stripe-elements。该代码库的文档非常不错,您可以查看一下。以下是我的使用方法

npm i vue-stripe-elements-plus --save

…或使用 Yarn

yarn add vue-stripe-elements-plus

现在让我们谈谈我们的购物车并将其集成。

购物车

以下是应用程序鸟瞰图的样子。我们已经讨论了函数和 Stripe 部分,现在让我们深入了解应用程序本身。

birds eye view of the application structure

在这些文章中,我们不会介绍整个应用程序的设置,而只介绍购物车和结账。如果您需要了解 Vue、Vuex 和 Nuxt 的基础知识,建议您在继续之前查看以下链接

在我们使用 Vuex 设置的通用商店中,我们保存了所有产品数据的清单,用于填充页面上的商品。我们还将使用这些信息填充一个(目前为空)购物车对象,以便将商品添加到其中进行购买。我们将在 pages 目录中的 `Cart.vue` 页面上使用这些数据。如果您不熟悉 Nuxt.js,它允许我们通过在 pages 目录中创建 `vue` 组件来将其用作页面。我们仍然可以使用 components 目录中的组件填充这些页面,以创建更模块化的应用程序。以下是我们现在讨论的部分

Showing we're discussing cart.vue and vuex in the application

我们需要从 Vuex 中的存储中获取两条信息:`cart` 的内容和 `cartTotal`。

我们将在 `pages/Cart.vue` 中使用计算属性来获取这些信息,以便我们可以在购物车中缓存和使用它们。

computed: {
  cart() {
    return this.$store.state.cart;
  },
  cartTotal() {
    return this.$store.state.cartTotal;
  },
  ...
}

…并且我们将创建一个新的计算属性,它也将存储购物车中商品的货币总计

computed: {
  ...
  total() {
    return Object.values(this.cart)
      .reduce((acc, el) => acc + (el.count * el.price), 0)
      .toFixed(2);
   }
}

我们将首先检查购物车中是否有商品。如果有,则需要检查是否已经处理了付款。我们需要这样做,因为如果购物车中没有商品或已经为添加的商品处理了付款,则无需显示结账表单。

<div v-if="cartTotal > 0">
  <!--we'll add our checkout here-->
</div>

<!--If the cart is empty, give them the ability to get back to the main page to add items-->
<div v-else-if="cartTotal === 0 && success === false" class="empty">
  <!--we'll add our empty state here-->
</div>

<!--If there's a success, let's let people know it's being processed, we'll add a success component later on-->
<div v-else>
  <!--we'll add success here-->
</div>

我们还将在我们的数据中创建一个 success 属性,我们将其初始设置为 `false`,并在稍后用于记录付款是否已成功提交。

data() {
  return {
    success: false
  };
},

如果存在购物车商品,我们希望显示它们、它们的单个总计(因为我们可以拥有多个相同商品的数量)以及最终总计。

<div v-if="cartTotal > 0">
  <h1>Cart</h1>
  
  <div class="cartitems"
    v-for="item in cart"
    key="item">
    <div class="carttext">
      <h4>{{ item.name }}</h4>
      <p>{{ item.price | usdollar }} x {{ item.count }}</p>
      <p>Total for this item: <strong>{{ item.price * item.count }}</strong></p>
    </div>
    <img class="cartimg" :src="`/${item.img}`" :alt="`Image of ${item.name}`">
  </div>

  <div class="total">
    <h3>Total: {{ total | usdollar }}</h3>
  </div>

  <!--we're going to add our checkout here-->
</div>

我们使用过滤器以美元格式化价格。我以这种方式格式化它们,而不是对其进行硬编码,以防将来需要支持其他货币。

filters: {
  usdollar: function(value) {
    return `$${value}`;
  }
}

设置结账组件

现在我们将创建我们的 `checkout` 组件,它将包含所有 Stripe 结账逻辑并连接到我们在 第二部分 中设置的无服务器函数。我们将在 `Cart.vue` 文件中注册该组件

import AppCheckout from './../components/AppCheckout.vue';

export default {
  components: {
    AppCheckout
  },
  ...
}

我们现在处于以下状态

Showing the Cart.vue in pages, as well as the checkout component

并且,在 `checkout` 组件本身中,我们将引入我们在 vue-stripe-elements 代码库文档中看到的该文件的基准

<template>
  <div id='app'>
    <h1>Please give us your payment details:</h1>
    <card class='stripe-card'
      :class='{ complete }'
      stripe='pk_test_XXXXXXXXXXXXXXXXXXXXXXXX'
      :options='stripeOptions'
      @change='complete = $event.complete'
    />
    <button class='pay-with-stripe' @click='pay' :disabled='!complete'>Pay with credit card</button>
  </div>
</template>
<script>
import { stripeKey, stripeOptions } from './stripeConfig.json'
import { Card, createToken } from 'vue-stripe-elements-plus'

export default {
  data () {
    return {
      complete: false,
      stripeOptions: {
        // see https://stripe.com/docs/stripe.js#element-options for details
      }
    }
  },

  components: { Card },

  methods: {
    pay () {
      // createToken returns a Promise which resolves in a result object with
      // either a token or an error key.
      // See https://stripe.com/docs/api#tokens for the token object.
      // See https://stripe.com/docs/api#errors for the error object.
      // More general https://stripe.com/docs/stripe.js#stripe-create-token.
      createToken().then(data => console.log(data.token))
    }
  }
}
</script>

接下来…

到目前为止,这就是该组件开箱即用的样子。我们将不得不稍微更新一下此组件以满足我们的需求,但不会太多。敬请期待明天的最后一期,届时我们将把我们的组件连接到我们的无服务器函数并完成结账!

文章系列

  1. 设置和测试
  2. Stripe 函数和托管
  3. 应用程序和结账组件(本文)
  4. 配置结账组件