vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue3微信支付宝PC端支付

Vue3实现微信支付宝PC端支付的步骤(附实例代码)

作者:韶鹿先生

因为公司项目涉及到充值功能所以做了支付宝、微信的支付功能,这篇文章主要介绍了Vue3实现微信支付宝PC端支付的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

前言

核心思想:无论是微信还是支付宝,PC端支付都遵循一个共同模式:“前端发起 -> 后端下单 -> 前端引导跳转/展示二维码 -> 用户支付 -> 后端处理回调”。前端的主要职责是**“发起”“引导”**。

下面我将分别详细讲解这两种支付方式的实现步骤,并提供Vue 3的代码示例。

准备工作

  1. 商户资质:你的公司需要在微信商户平台支付宝开放平台注册并签约相关支付产品(如微信的Native支付、支付宝的电脑网站支付)。
  2. 后端接口:你需要后端同学提供以下接口:
    • 微信支付下单接口:例如 POST /api/payment/wechat-native。前端传递商品ID、金额等信息,后端调用微信统一下单API后,返回一个二维码链接 (code_url)。
    • 支付宝支付下单接口:例如 POST /api/payment/alipay-pc。前端传递信息,后端调用支付宝下单API后,返回一个包含完整form表单的HTML字符串
    • 支付状态查询接口:例如 GET /api/payment/status?orderId=xxx。前端用于在用户支付后,主动向后端查询订单是否已成功。
  3. 前端环境:Vue 3 + axios (用于API请求)。

一、 微信支付 (Native Pay / 扫码支付)

微信PC端支付最常用的方式是 Native Pay,即在网页上显示一个二维码,用户用手机微信扫码完成支付。

流程分解

  1. 创建订单:用户在你的网站上点击“去支付”。
  2. 前端请求下单:前端调用后端的微信支付下单接口,并传递订单信息。
  3. 后端返回二维码链接:后端与微信服务器交互后,会得到一个 code_url,这是一个特殊的URL,内容是微信支付二维码的信息。后端将这个 code_url 返回给前端。
  4. 前端生成并展示二维码:前端使用一个二维码生成库(如 qrcode.vue)将 code_url 转换成二维码图片并显示出来。
  5. 前端轮询支付状态:在二维码显示后,前端启动一个定时器,每隔几秒钟就调用后端的“支付状态查询接口”,询问订单是否已支付成功。
  6. 用户扫码支付:用户用手机微信扫描二维码,输入密码完成支付。
  7. 后端接收异步通知:微信服务器会将支付成功的结果通过一个异步的HTTP请求(回调)通知到你的后端服务器。后端收到通知后,更新订单状态为“已支付”。
  8. 前端轮询得知成功:前端的轮询请求最终会从后端那里得到“已支付”的状态,此时前端停止轮询,并给用户显示支付成功的提示,然后跳转到成功页面。

Vue 3 代码实现 (Payment.vue)

1. 安装二维码库

npm install qrcode.vue

2. 编写组件

<template>
  <div class="payment-container">
    <h2>订单支付</h2>
    <div v-if="!paymentSuccess">
      <div v-if="wechatCodeUrl" class="qrcode-section">
        <h3>微信支付</h3>
        <p>请使用微信扫描下方二维码完成支付</p>
        <qrcode-vue :value="wechatCodeUrl" :size="200" level="H" />
        <p class="notice">二维码将在 {{ countdown }} 秒后过期</p>
      </div>
      <div v-else>
        <p>正在生成支付二维码,请稍候...</p>
      </div>
    </div>
    <div v-if="paymentSuccess">
      <h3>支付成功!</h3>
      <p>正在跳转到订单详情页面...</p>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import QrcodeVue from 'qrcode.vue';
import axios from 'axios'; // 假设已配置

const route = useRoute();
const router = useRouter();

const wechatCodeUrl = ref('');
const paymentSuccess = ref(false);
const countdown = ref(300); // 假设二维码5分钟过期

let pollTimer = null;
let countdownTimer = null;

const orderId = route.query.orderId; // 从路由获取订单ID

// 1. 获取微信支付二维码
const getWechatPayQrcode = async () => {
  try {
    const response = await axios.post('/api/payment/wechat-native', { orderId });
    wechatCodeUrl.value = response.data.code_url;
    // 成功获取二维码后,开始轮询和倒计时
    startPolling();
    startCountdown();
  } catch (error) {
    console.error('获取微信支付二维码失败:', error);
    alert('支付二维码生成失败,请重试!');
  }
};

// 2. 轮询支付状态
const checkPaymentStatus = async () => {
  try {
    const response = await axios.get(`/api/payment/status?orderId=${orderId}`);
    if (response.data.status === 'SUCCESS') {
      paymentSuccess.value = true;
      stopPolling(); // 支付成功,停止轮询
      // 跳转到成功页面
      setTimeout(() => {
        router.push(`/order-detail/${orderId}`);
      }, 2000);
    }
  } catch (error) {
    console.error('查询支付状态失败:', error);
  }
};

const startPolling = () => {
  // 每3秒查询一次
  pollTimer = setInterval(checkPaymentStatus, 3000);
};

const stopPolling = () => {
  if (pollTimer) {
    clearInterval(pollTimer);
  }
  if (countdownTimer) {
      clearInterval(countdownTimer);
  }
};

const startCountdown = () => {
    countdownTimer = setInterval(() => {
        if(countdown.value > 0) {
            countdown.value--;
        } else {
            stopPolling();
            alert('二维码已过期,请刷新页面重试');
        }
    }, 1000);
}


onMounted(() => {
  if (orderId) {
    getWechatPayQrcode();
  } else {
      alert('订单ID不存在!');
  }
});

// 组件卸载时,清除定时器,避免内存泄漏
onUnmounted(() => {
  stopPolling();
});
</script>

<style scoped>
.payment-container {
  text-align: center;
  padding: 40px;
}
.qrcode-section {
  display: inline-block;
  border: 1px solid #eee;
  padding: 20px;
}
.notice {
    color: #999;
}
</style>

二、 支付宝支付 (电脑网站支付)

支付宝PC端支付通常是跳转到一个新的页面(支付宝的收银台),用户在那个页面完成支付后,再跳回你的网站。

流程分解

  1. 创建订单:同微信支付。
  2. 前端请求下单:前端调用后端的支付宝支付下单接口。
  3. 后端返回Form表单:后端与支付宝服务器交互后,支付宝会返回一段包含支付信息的、会自动提交的HTML Form表单字符串。后端将这个字符串原封不动地返回给前端。
  4. 前端执行页面跳转:前端接收到这个HTML字符串后,不能直接用 v-html 渲染它。正确的做法是创建一个新的空白页面(或iframe),将这段HTML写入其中。浏览器解析后,表单会自动提交,页面就会跳转到支付宝的收银台。
  5. 用户在支付宝页面支付:用户扫码或登录支付宝账号完成支付。
  6. 支付宝同步跳转 (Return URL):用户支付成功后,支付宝会根据你后端配置的 return_url,将用户的浏览器重定向回你的网站的某个页面(例如支付成功页),并在URL中附带上订单号、支付金额等参数。
  7. 前端处理同步跳转:前端的成功页面从URL中获取参数,可以先给用户一个“支付成功”的初步提示。但此时不能100%确认支付成功,因为这个跳转是可以被伪造的。
  8. 后端接收异步通知 (Notify URL):与此同时,支付宝服务器也会向你后端配置的 notify_url 发送一个异步的POST请求,这才是确认支付成功的最终依据。后端收到通知并验签成功后,才会更新订单状态。
  9. 前端确认最终状态:前端成功页面最好再调用一次“支付状态查询接口”来获取最准确的订单状态,然后向用户展示最终结果。

Vue 3 代码实现

1. 支付发起组件 (Payment.vue)

<template>
  <div class="payment-container">
    <h2>订单支付</h2>
    <button @click="handleAlipay">使用支付宝支付</button>
    <!-- 这里就是用来接收和提交支付宝表单的容器 -->
    <div ref="alipayFormContainer"></div>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { useRoute } from 'vue-router';
import axios from 'axios';

const route = useRoute();
const orderId = route.query.orderId;
const alipayFormContainer = ref(null); // 用于获取DOM元素

const handleAlipay = async () => {
  try {
    const response = await axios.post('/api/payment/alipay-pc', { orderId });
    const formHtml = response.data.form_html;

    // **关键步骤:提交支付宝返回的表单**
    if (alipayFormContainer.value) {
      // 1. 将表单HTML写入容器
      alipayFormContainer.value.innerHTML = formHtml;
      // 2. 找到表单并触发表单提交
      const form = alipayFormContainer.value.querySelector('form');
      if (form) {
        form.submit();
      } else {
        throw new Error('Alipay form not found in response.');
      }
    }
  } catch (error) {
    console.error('支付宝支付发起失败:', error);
    alert('支付失败,请稍后重试!');
  }
};
</script>

2. 支付成功回调页面 (PaymentSuccess.vue)

你需要一个专门的路由和页面来接收支付宝的同步跳转。

// 在 router/index.js 中配置路由
// { path: '/payment/success', name: 'PaymentSuccess', component: PaymentSuccess }

// PaymentSuccess.vue
<template>
  <div class="result-container">
    <div v-if="loading">正在确认支付结果...</div>
    <div v-else-if="paymentSuccess">
      <h3>支付成功!</h3>
      <p>订单号:{{ orderId }}</p>
    </div>
    <div v-else>
      <h3>支付结果确认失败</h3>
      <p>请稍后到您的订单中心查看最新状态。</p>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import axios from 'axios';

const route = useRoute();
const loading = ref(true);
const paymentSuccess = ref(false);
const orderId = ref('');

onMounted(async () => {
  // 从支付宝同步跳转的URL中获取订单号
  orderId.value = route.query.out_trade_no;

  if (orderId.value) {
    try {
      // 再次向自己的后端查询,获取最准确的支付状态
      const response = await axios.get(`/api/payment/status?orderId=${orderId.value}`);
      if (response.data.status === 'SUCCESS') {
        paymentSuccess.value = true;
      }
    } catch (error) {
      console.error('确认支付状态失败:', error);
    } finally {
      loading.value = false;
    }
  } else {
      loading.value = false;
  }
});
</script>

总结与对比

特性微信支付 (Native)支付宝支付 (电脑网站)
交互方式内嵌二维码,不离开当前网站跳转到支付宝网站
前端核心任务1. 请求code_url
2. 生成二维码
3. 轮询支付状态
1. 请求form_html
2. 动态创建并提交表单
结果确认依赖前端轮询获取最终状态依赖同步跳转(return_url) + 最终状态查询
用户体验在当前页完成,体验更连贯页面跳转,体验有中断感

问题1:支付宝能不能像微信支付一样也采用短轮询的方式

完全可以! 支付宝同样支持通过短轮询的方式来处理支付结果,而且在某些场景下,这种方式的用户体验会优于页面跳转。

短轮询的方式,对应的是支付宝的 “当面付” 产品中的 “扫码支付” 功能。虽然它的名字叫“当面付”,但它并非只能用于线下场景。线上PC网站完全可以使用它来实现和微信Native Pay(扫码支付)一模一样的用户体验。

下面详细讲解如何使用支付宝的“扫码支付”配合前端轮询来实现PC端支付。

支付宝“扫码支付”(当面付)的工作流程

这个流程和我们之前讨论的微信扫码支付几乎完全一致:

  1. 签约产品:确保你的支付宝开放平台账号已经签约了**“当面付”** 产品。

  2. 创建订单:用户在你的网站上点击“去支付”。

  3. 前端请求下单:前端调用后端的支付宝下单接口。这里与“电脑网站支付”的下单接口是不同的。例如 POST /api/payment/alipay-qrcode

  4. 后端调用支付宝“统一收单交易预创建”接口

    • 后端不再是调用 alipay.trade.page.pay (电脑网站支付接口)。
    • 而是调用 alipay.trade.precreate (扫码支付的预创建接口)。
    • 这个接口成功后,支付宝会返回一个二维码链接 (qr_code),这个链接的内容就是支付宝支付二维码的信息。
  5. 后端返回二维码链接给前端:后端将从支付宝获取的 qr_code 字符串返回给前端。

  6. 前端生成并展示二维码:前端拿到这个 qr_code 字符串,使用二维码生成库(如 qrcode.vue)将其渲染成一个可供扫描的二维码图片,并展示在当前页面上。

  7. 前端启动轮询:在二维码显示的同时,前端启动一个定时器,每隔几秒钟就调用后端的“支付状态查询接口”(这个查询接口可以和微信共用),主动询问订单的支付状态。

  8. 用户扫码支付:用户打开手机支付宝App,使用“扫一扫”功能扫描网页上的二维码,并完成支付。

  9. 后端接收异步通知 (Notify URL):用户支付成功后,支付宝服务器会向你后端配置的 notify_url 发送异步通知。后端接收到通知并验签成功后,更新订单状态为“已支付”。

  10. 前端轮询得知成功:前端的轮询请求最终会从后端那里得到“已支付”的状态。此时,前端停止轮询,并给用户显示支付成功的提示,然后跳转到成功页面或更新UI。

与“电脑网站支付”的核心区别

特性支付宝“扫码支付”(当面付)支付宝“电脑网站支付”
后端调用接口alipay.trade.precreatealipay.trade.page.pay
后端返回值二维码链接字符串 (qr_code)一段可自动提交的HTML Form表单
前端处理方式内嵌二维码 + 前端轮询新页面跳转
用户体验在当前网站完成支付,不跳转,体验流畅跳转到支付宝网站,支付完成后再跳回,体验有中断感
适用场景需要在网页内完成支付的场景,用户体验更佳任何PC网站支付,实现简单,是传统的PC支付方式

Vue 3 代码实现(轮询方式)

你会发现,这段代码和我们之前写的微信支付的代码几乎完全一样,只是API地址和返回字段名可能不同。这正是轮询方式的优点之一:前端逻辑可以高度复用

<template>
  <div class="payment-container">
    <h2>选择支付方式</h2>
    <div>
      <button @click="initiatePayment('wechat')">微信支付</button>
      <button @click="initiatePayment('alipay')">支付宝支付</button>
    </div>

    <!-- 统一的二维码展示区域 -->
    <div v-if="qrcodeUrl" class="qrcode-section">
      <h3>请使用{{ paymentMethod === 'wechat' ? '微信' : '支付宝' }}扫码支付</h3>
      <qrcode-vue :value="qrcodeUrl" :size="200" level="H" />
      <p>二维码有效时间剩余 {{ countdown }} 秒</p>
    </div>
  </div>
</template>

<script setup>
import { ref, onUnmounted } from 'vue';
import { useRoute } from 'vue-router';
import QrcodeVue from 'qrcode.vue';
import axios from 'axios';

const route = useRoute();
const orderId = route.query.orderId;

const paymentMethod = ref('');
const qrcodeUrl = ref('');
const countdown = ref(300);

let pollTimer = null;
let countdownTimer = null;

// 发起支付(根据选择的支付方式)
const initiatePayment = async (method) => {
  // 清理之前的状态
  stopPolling();
  qrcodeUrl.value = '';
  paymentMethod.value = method;

  try {
    let apiUrl = '';
    if (method === 'wechat') {
      apiUrl = '/api/payment/wechat-native';
    } else if (method === 'alipay') {
      apiUrl = '/api/payment/alipay-qrcode'; // 调用支付宝扫码支付的下单接口
    }

    const response = await axios.post(apiUrl, { orderId });
    
    // 根据不同接口返回的字段名获取二维码链接
    qrcodeUrl.value = (method === 'wechat') ? response.data.code_url : response.data.qr_code;
    
    // 开始轮询和倒计时
    startPolling();
    startCountdown();
  } catch (error) {
    console.error(`${method}支付二维码生成失败:`, error);
    alert('支付二维码生成失败,请重试!');
  }
};

// 轮询支付状态(完全可复用)
const checkPaymentStatus = async () => {
  try {
    const response = await axios.get(`/api/payment/status?orderId=${orderId}`);
    if (response.data.status === 'SUCCESS') {
      stopPolling();
      alert('支付成功!');
      // router.push(...);
    }
  } catch (error) {
    console.error('查询支付状态失败:', error);
  }
};

const startPolling = () => {
  pollTimer = setInterval(checkPaymentStatus, 3000);
};

const startCountdown = () => {
  countdown.value = 300; // 重置倒计时
  countdownTimer = setInterval(() => {
    if (countdown.value > 0) {
      countdown.value--;
    } else {
      stopPolling();
      qrcodeUrl.value = ''; // 清空二维码
      alert('二维码已过期,请重新选择支付方式');
    }
  }, 1000);
};

const stopPolling = () => {
  if (pollTimer) clearInterval(pollTimer);
  if (countdownTimer) clearInterval(countdownTimer);
};

onUnmounted(() => {
  stopPolling();
});
</script>

总结

答案是肯定的。支付宝的“当面付-扫码支付”产品就是为了实现与微信Native Pay类似的用户体验而设计的。

选择哪种支付宝支付方式?

对于一个同时需要支持微信和支付宝扫码支付的PC网站,采用轮询方案可以让你的前端代码逻辑高度统一,维护起来更加方便。

到此这篇关于Vue3实现微信支付宝PC端支付的文章就介绍到这了,更多相关Vue3微信支付宝PC端支付内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文