在做一些支付业务的时候,对接第三方的支付平台,在前端页面就会经常使用到 打开新窗口 跳转到第三方的支付页上去的场景。那么就会有以下几种场景需求

  1. 打开新窗口,给定一个 URL 地址
  2. 打开新窗口,给定一段 HTML,这个 html 是第三方平台返回的自提交 html(比如支付宝)
  3. 可能需要监听打开的窗口是否有关闭

打开新窗口,给定 URL 地址

  1. // payUrl 展示开地址的内容
  2. const orderWindow = window.open(payUrl, '_blank', 'width=' + (window.screen.availWidth - 10) + ',height=' + (window.screen.availHeight - 30) + ',top=0,left=0,toolbar=no,menubar=no,scrollbars=no, resizable=no,location=no, status=no')

上面的代码是打开一个新窗口(近乎于全屏的设置),具体的 open 参数含义可以参考 w3c 或则 这个网站

打开新窗口,给定 html 展示

  1. // url 给一个空字符串
  2. const orderWindow = window.open('', '_blank', 'width=' + (window.screen.availWidth - 10) + ',height=' + (window.screen.availHeight - 30) + ',top=0,left=0,toolbar=no,menubar=no,scrollbars=no, resizable=no,location=no, status=no')
  3. // 拿到返回的对象后,将我们自己的 html 写入
  4. orderWindow.document.write(payHtml)
  5. orderWindow.focus() // 让原窗口获取焦点

监听打开的窗口是否关闭

有时候可能会有打开了支付窗口之后,但是用户关闭了,如何处理?
image.png
如上图所示,打开新窗口后,原来的页面,你需要间隔的去后台检查这个支付结果,支付完成后,就关闭这个 loading 效果。 正常情况下,新打开的窗口在跳转到支付平台后,支付完成后,会跳转到我们自定义的一个前端页面,这个前端页面,你展示一个结果,然后关闭掉就可以了。

但是这里需要处理 窗口 和 原页面的 loading 交互效果

  1. /**
  2. * 检查支付结果,并且检测打开的新窗口状态,新窗口关闭后,在超时后自动重置 loading 状态
  3. * @param inId 预下单的自定义系统ID,用于像后台获取支付结果,这个结果是支付平台通过异步回调方式通知到后端系统的
  4. * @param orderWindow 新打开的窗口
  5. */
  6. preOrderSuccessCheckResultAndMonitoringWindow (inId, orderWindow) {
  7. // loading 开关
  8. this.payResultLoading = true
  9. this.windowTimeout = 0 // 发起新的请求时,重置
  10. // 通过每间隔 5 秒检查一次 窗口的 closed 状态,来检查是否已经关闭
  11. const timer = setInterval(() => {
  12. // 如果窗口已关闭
  13. if (orderWindow.closed) {
  14. // 正常支付完成后关闭,最多再等待 10 秒钟
  15. if (this.windowTimeout === 0) {
  16. this.windowTimeout = 10
  17. } else {
  18. // 最多再等待 10 秒,就主动关闭 loading
  19. this.windowTimeout = this.windowTimeout - 5
  20. if (this.windowTimeout <= 0) {
  21. clearTimeout(timer)
  22. this.payResultLoading = false
  23. this.windowTimeout = 0
  24. }
  25. }
  26. }
  27. // 每次去后端检查结果,如果已经成功,就清除定时器和关闭 loading
  28. this.getPayResult(timer, inId)
  29. }, 5000)
  30. this.payResultTimer = timer
  31. },

上面的代码就会实现:

  1. 如果是正常支付完成,新窗口里面最后会跳转到我们前端的一个自定义结果页,你可以设置 5 秒后自动关闭新窗口,关闭窗口的代码为 **_window_**.close**_()_**
  2. 如果是人为的直接将新窗口关闭,那么原页面的 loading 效果最多会持续 10 秒种,10 秒后就会关闭