基于vue2的h5页面实现拉起支付宝app支付且轮询支付结果
*只有前端部分
1.首先data需要储存几个值:
payUrl: "", // 订单支付跳转链接
isFetchCode: false, //正在生成订单
payStatus: "", // 订单状态,用于判断是否还需要继续请求订单支付结果接口
userDown: false, // 用户点击已支付完成按钮
timer: null, // 轮询计时器
goZfbSrc: null, // 用于解决ios系统下safari浏览器不支持window新开窗口的计时器
以及其他订单进行中弹窗、支付成功弹窗等状态管理
2.用户点击支付后,请求后端接口,拿到支付宝跳转链接:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | // 点击购买,获取商品支付地址 async showQrCode() { if ( this .isFetchCode) return ; this .isFetchCode = true ; try { const { code, msg, data } = await api.createOrder({ ...传参 }); if (code === 0 && data) { const { jump_url, orderno, create_dt } = data; // 获取订单编号及下单时间 this .orderno = orderno; this .createTime = create_dt; this .payUrl = jump_url; // 关闭下单弹窗 this .payVisible = false ; // 打开订单进行中弹窗 this .codeVisible = true ; // 支付宝支付 if ( this .payType === "alipay_mobile" ) { // 微信浏览器中选择支付宝支付,弹窗复制支付链接,提示用户在外部浏览器打开进行支付 const browser = window.navigator.userAgent.toLowerCase(); if (browser.match(/MicroMessenger/i) == "micromessenger" ) { this .copyVisible = true ; } else { // 跳转支付宝 this .payStatus = "waiting" ; this .pollOrder(); this .goZfbSrc = setTimeout(() => { window.open(jump_url, "_blank" ); clearTimeout( this .goZfbSrc); }); // window.location.replace(jump_url); // const a = document.createElement("a"); // a.setAttribute("href", jump_url); // a.setAttribute("target", "支付"); // document.body.appendChild(a); // a.click(); // document.body.removeChild(a); // const form = document.createElement("form"); // form.action = jump_url; // form.target = "_blank"; // form.method = "POST"; // document.body.appendChild(form); // form.submit(); // const tempPage = window.open("_blank"); // tempPage.location = jump_url; // window.open(jump_url, "_ blank"); } } else { // 微信支付 this .$toast( "微信支付" ); // this.initiatePayment(); } } else if (code === 87) { // 限购,打开限购弹窗 this .$refs.fail.visible = true ; } else if (code === 83) { this .$toast( "订单生成失败,请重新选择商品购买,如有疑问请咨询客服查询" ); } else { this .$toast(msg || "获取失败" ); } } catch (err) { // } finally { this .isFetchCode = false ; } }, |
肉眼可见为了这个该死的sarari尝试了多少种方案= =无论是创建a标签手动触发点击事件,还是通过创建表单通过提交表单的方式拉起,还是直接使用window.open开新窗口,都不可以,最终是利用了setTimeout这个利器才解决这个问题。
而safari不允许的原因也很简单,它默认开启了阻止弹出窗口的策略,禁用了通过代码调用超链接在新标签打开页面的功能,避免window.open被滥用。但这个阻止弹出窗口的操作,并不是完全禁止,而是会根据用户的行为来判断这次window.open()是否属于流氓操作。
所以,聪明的程序员利用setTimeout运行于主线程的这个特点,把打开链接的操作放到setTimeout里运行即可,这样就不会被浏览器认定为代码操作,避免了被拦截。
谢谢你,大佬。(虎目含泪)
2.实现拉起app之后,接着就是页面轮询了:
1 2 3 4 5 6 7 8 9 10 11 12 13 | // 间隔刷新订单支付状态 pollOrder() { this .timer = setInterval(() => { if ( this .payStatus === "waiting" && this .codeVisible) { // 未完成且订单进行中的弹窗未关闭,则继续请求 this .queryPayStatus(); } else { // 已成功完成/关闭弹窗,清空计时器 clearInterval( this .timer); this .timer = null ; } }, 3000); }, |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | // 查询支付状态 async queryPayStatus() { try { const { code } = await api.orderPolling({ orderno: this .orderno, }); if (code === 0) { this .payStatus = "success" ; this .codeVisible = false ; this .sucVisible = true ; clearInterval( this .timer); } else if (code === 22) { this .payStatus = "" ; this .$toast( "订单已失效,请重新购买" ); this .codeVisible = false ; clearInterval( this .timer); } else { // 如果是用户手动查询,弹出状态提示 if ( this .userDown) { this .$toast( "订单未完成支付,请确认支付状态" ); this .userDown = false ; } } } catch (err) { // } finally { // } }, |
3.以及手动点击查询:
1 2 3 4 5 | // 用户点击刷新支付状态 userSearchStatus() { this .userDown = true ; this .queryPayStatus(); }, |
那么简单的h5页面拉起支付宝支付就完成鸟~
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2022-12-19 js处理树形数组扁平化