欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 培训 > 基于Vue 3的智能支付二维码弹窗组件设计与实现

基于Vue 3的智能支付二维码弹窗组件设计与实现

2025/4/20 4:36:54 来源:https://blog.csdn.net/qq_39842184/article/details/146215905  浏览:    关键词:基于Vue 3的智能支付二维码弹窗组件设计与实现

前言

本文是集成qrcode-vue3和element的弹窗  请先下载qrcode-vue3 
npm install qrcode-vue3 --save

完整组件代码如下

<script setup lang="ts">
import { ref, computed, watch, onUnmounted } from 'vue'
import QRCodeVue3, { type QRCodeProps } from 'qrcode-vue3'
import type { OrderStatus } from '@/api/types' // 根据实际类型定义调整interface Props {modelValue: booleanvalue: stringorderId: string | numbersize?: numberpollInterval?: numbertimeout?: numberimageOptions?: QRCodeProps['imageOptions']qrOptions?: QRCodeProps['qrOptions']downloadOptions?: QRCodeProps['downloadOptions']
}const props = withDefaults(defineProps<Props>(), {size: 200,pollInterval: 3000, // 3秒轮询timeout: 60000,     // 60秒超时imageOptions: () => ({hideBackgroundDots: true,imageSize: 0.4,margin: 0}),qrOptions: () => ({typeNumber: 0,mode: 'Byte',errorCorrectionLevel: 'H'}),downloadOptions: () => ({name: 'qrcode',extension: 'png'})
})const emit = defineEmits(['update:modelValue', 'success', 'timeout'])const dialogVisible = computed({get: () => props.modelValue,set: (value) => emit('update:modelValue', value)
})const remainingTime = ref(0)
const pollingTimer = ref<number>()
const countdownTimer = ref<number>()// 默认二维码样式配置
const defaultDotsOptions = {type: 'dots',color: '#26249a',gradient: {type: 'linear',rotation: 0,colorStops: [{ offset: 0, color: '#26249a' },{ offset: 1, color: '#26249a' }]}
}const defaultCornersOptions = {squareOptions: { type: 'dot', color: '#000000' },dotOptions: { type: undefined, color: '#000000' }
}const startPolling = () => {stopPolling() // 先停止已有轮询remainingTime.value = Math.floor(props.timeout / 1000)// 启动倒计时countdownTimer.value = window.setInterval(() => {remainingTime.value -= 1if (remainingTime.value <= 0) {handleTimeout()}}, 1000)// 立即执行第一次查询pollOrderStatus()
}const pollOrderStatus = async () => {try {const result = await getPayResultById(props.orderId) // 替换为实际的API调用if (result.success) {emit('success', result.data)closeDialog()return}} catch (error) {console.error('轮询请求失败:', error)}// 继续轮询if (remainingTime.value > 0) {pollingTimer.value = window.setTimeout(pollOrderStatus, props.pollInterval)}
}const handleTimeout = () => {emit('timeout')closeDialog()
}const closeDialog = () => {dialogVisible.value = falsestopPolling()
}const stopPolling = () => {clearTimeout(pollingTimer.value)clearInterval(countdownTimer.value)pollingTimer.value = undefinedcountdownTimer.value = undefined
}// 监听弹窗显示状态
watch(() => props.modelValue, (newVal) => {if (newVal) {startPolling()} else {stopPolling()}
})// 组件卸载时清除定时器
onUnmounted(stopPolling)// 格式化剩余时间显示
const formatTime = (seconds: number) => {const mins = Math.floor(seconds / 60)const secs = seconds % 60return `${mins}:${secs.toString().padStart(2, '0')}`
}
</script><template><el-dialogv-model="dialogVisible":title="`扫描二维码 (剩余时间 ${formatTime(remainingTime)})`"class="qr-code-dialog"width="auto"@closed="stopPolling"><div class="qr-container"><QRCodeVue3:value="value":width="size":height="size":qr-options="qrOptions":image-options="imageOptions":dots-options="defaultDotsOptions":corners-square-options="defaultCornersOptions.squareOptions":corners-dot-options="defaultCornersOptions.dotOptions":background-options="{ color: '#ffffff' }":download="true":download-options="downloadOptions"/></div><template #footer><el-button type="danger" @click="closeDialog">关闭二维码 ({{ formatTime(remainingTime) }})</el-button></template></el-dialog>
</template><style scoped lang="scss">
.qr-code-dialog {.qr-container {padding: 20px;display: flex;justify-content: center;align-items: center;background: #fff;border-radius: 8px;}:deep(.el-dialog__header) {margin-right: 0;}:deep(.el-dialog__body) {padding: 0;}
}
</style>

一、应用场景

在支付类系统中,我们经常需要实现这样的功能:当用户发起支付请求后,展示支付二维码,并持续轮询服务器查询支付状态。本文介绍的组件完美解决了以下需求:

  1. 动态二维码展示:支持自定义样式和参数

  2. 状态轮询机制:自动查询支付结果

  3. 智能超时处理:60秒自动销毁二维码

  4. 事件驱动机制:支付成功/超时事件通知

  5. 用户体验优化:实时倒计时显示

二、核心功能设计

1. 组件参数设计

interface Props {modelValue: boolean    // 控制弹窗显示value: string          // 二维码内容orderId: string | number // 订单IDsize?: number          // 二维码尺寸(默认200px)pollInterval?: number  // 轮询间隔(默认3000ms)timeout?: number       // 超时时间(默认60000ms)// ...其他二维码配置参数
}

2. 生命周期管理

sequenceDiagramparticipant Usercomponent Componentcomponent ServerUser->>Component: 打开弹窗Component->>Server: 首次查询支付状态Server-->>Component: 返回支付状态loop 轮询周期Component->>Server: 定时查询状态Server-->>Component: 返回最新状态endalt 支付成功Component->>User: 触发success事件else 超时未支付Component->>User: 触发timeout事件end

三、关键技术实现

1. 复合定时器管理

const startPolling = () => {// 启动倒计时countdownTimer.value = window.setInterval(() => {remainingTime.value -= 1if (remainingTime.value <= 0) handleTimeout()}, 1000)// 轮询逻辑const poll = async () => {if (remainingTime.value <= 0) returntry {const result = await getPayResultById(props.orderId)if (result.success) {emit('success', result.data)closeDialog()} else {pollingTimer.value = window.setTimeout(poll, props.pollInterval)}} catch (error) {pollingTimer.value = window.setTimeout(poll, props.pollInterval)}}poll()
}

实现亮点

  • 双定时器独立管理(倒计时+轮询)

  • 错误边界处理:网络异常时自动重试

  • 自动清理机制:组件卸载时清除定时器

2. 响应式时间显示

<template><el-dialog :title="`扫描二维码 (剩余时间 ${formatTime(remainingTime)})`"><!-- ... --><el-button>关闭二维码 ({{ formatTime(remainingTime) }})</el-button></el-dialog>
</template><script>
const formatTime = (seconds: number) => {const mins = Math.floor(seconds / 60)const secs = seconds % 60return `${mins}:${secs.toString().padStart(2, '0')}`
}
</script>

四、组件集成使用

1. 基础使用示例

<template><QrPaymentDialogv-model="showDialog":value="qrUrl":order-id="orderId"@success="handleSuccess"@timeout="handleTimeout"/>
</template><script setup>
const handleSuccess = (orderData) => {ElNotification.success('支付成功')router.push('/payment/success')
}const handleTimeout = () => {ElMessage.error('支付超时')// 重新生成订单...
}
</script>

2. 自定义配置示例

<QrPaymentDialog:size="300":poll-interval="5000" :timeout="120000":download-options="{name: 'wechat-pay',extension: 'jpg'}"
/>

五、性能优化实践

  1. 定时器优化

    onUnmounted(() => {clearTimeout(pollingTimer.value)clearInterval(countdownTimer.value)
    })

  2. 渲染优化

    <QRCodeVue3v-if="dialogVisible" <!-- 仅在可见时渲染 -->
    />

  3. 网络请求优化

    let isPending = falseconst poll = async () => {if (isPending) returnisPending = truetry {// 请求处理...} finally {isPending = false}
    }

六、扩展方向建议

  1. 二维码刷新机制

    const refreshQR = () => {qrVersion.value++ // 通过key强制重新渲染
    }

  2. 支付方式切换

    <template><el-radio-group v-model="payMethod"><el-radio label="wechat">微信</el-radio><el-radio label="alipay">支付宝</el-radio></el-radio-group>
    </template>

  3. 多通道轮询

    const channels = ['/api/pay/status', '/api/pay/backup-status']
    let currentChannel = 0const poll = () => {get(channels[currentChannel]).catch(() => {currentChannel = (currentChannel + 1) % channels.length})
    }

七、最佳实践建议

  1. 服务端配合优化

    • 实现幂等性查询接口

    • 设置合适的HTTP缓存头

    • 返回扩展状态码(如:100-继续轮询,200-支付成功)

  2. 前端监控

    const poll = async () => {const start = Date.now()try {await getPayResult()} finally {const duration = Date.now() - starttrackApiPerformance(duration) // 上报性能数据}
    }

  3. 降级方案

    <template><div v-if="qrError" class="fallback"><p>二维码加载失败</p><button @click="retry">重新生成</button></div>
    </template>

八、总结

本文介绍的智能支付二维码组件具有以下优势:

特性优势说明
开箱即用简单props配置即可快速集成
高可定制性支持样式/定时策略全方位定制
健壮性完善的错误处理和定时器清理机制
良好的用户体验实时反馈+倒计时提示
类型安全完整的TypeScript支持

如果对你有帮助,请帮忙点个赞

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com