基于vue2的h5页面实现拉起支付宝app支付且轮询支付结果
*只有前端部分
1.首先data需要储存几个值:
payUrl: "", // 订单支付跳转链接
isFetchCode: false, //正在生成订单
payStatus: "", // 订单状态,用于判断是否还需要继续请求订单支付结果接口
userDown: false, // 用户点击已支付完成按钮
timer: null, // 轮询计时器
goZfbSrc: null, // 用于解决ios系统下safari浏览器不支持window新开窗口的计时器
以及其他订单进行中弹窗、支付成功弹窗等状态管理
2.用户点击支付后,请求后端接口,拿到支付宝跳转链接:
// 点击购买,获取商品支付地址
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之后,接着就是页面轮询了:
// 间隔刷新订单支付状态
pollOrder() {
this.timer = setInterval(() => {
if (this.payStatus === "waiting" && this.codeVisible) {
// 未完成且订单进行中的弹窗未关闭,则继续请求
this.queryPayStatus();
} else {
// 已成功完成/关闭弹窗,清空计时器
clearInterval(this.timer);
this.timer = null;
}
}, 3000);
},
// 查询支付状态
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.以及手动点击查询:
// 用户点击刷新支付状态
userSearchStatus() {
this.userDown = true;
this.queryPayStatus();
},
那么简单的h5页面拉起支付宝支付就完成鸟~

浙公网安备 33010602011771号