微信H5如何关闭浏览器(如何监听手机的物理返回键)

一、背景

背景是这样的:该项目进入h5时会通过 location.replace(xxx) 或 location.href = xxx 跳转到某个地址①,该地址会请求获得微信 openId;获取成功后再重定向到h5首页。

那么问题来了,重定向会在微信浏览器留下一条 history 记录,那么我在h5首页按手机的物理返回键,就不会因为已是第一页而退出浏览器,而是跳回地址①,再重定向到首页;按返回键又回到①,又重定向到首页。。。除非手速够快,不然就会形成“死循环”。

那么,怎样能在首页按返回键时,直接关闭微信浏览器呢?

二、解决思路

解决思路很自然:

1、在首页监听手机何时被按下返回键;

2、当发生1中事件时,截停浏览器默认事件(不返回history中的重定向页);

3、然后执行自定义事件(关闭微信浏览器)。

三、解决方法

1、在首页监听手机何时被按下返回键

监听 popstate 事件。其实并没有严格意义上的“按下物理返回键”事件,但手机的物理返回键其实作用就跟浏览器左上角的 “←” 按钮作用相似,都是返回上一个页面(也就是history中的上一条记录)。而浏览器中返回上一条 history 记录时触发了 “popstate” 事件。因此我们可以利用 “popstate” 来模拟 “按下物理返回键” 事件。

代码:

// 本示例使用了 vue3 + typescript。其他框架类似,在组件创建、挂载时加上这个事件监听;

function closeWXWindow() {
  // TODO: 关闭微信浏览器
}

onMounted(() => {
  window.addEventListener('popstate', closeWXWindow);
});

// 记得离开该页面时取消监听,否则在其他页面按返回键也会直接关闭浏览器了~
onUnmounted(() => {
  window.removeEventListener('popstate', closeWXWindow);
});

2、当发生1中事件时,截停浏览器默认事件(不返回history中的重定向页)

这个稍微有点小复杂~

大家乍一看可能脱口而出:“这个我熟!在事件处理函数里加一行 event.preventDefault() 嘛!”

遗憾的是,即使用上这么一行,浏览器还是会回到上一级页面。其实可以这么理解:正是因为返回了上一级页面,所以才会有 "popstate" 事件;而不是有了 “popstate” 事件,然后才去执行返回上一级页面的默认行为。

所以说,按下返回键后,“返回上一级页面” 这个动作,浏览器无论如何都会执行

直接截停是没戏了,但咱们可以模拟呀——只要上一级页面跟当前页面是同一个页面,那返回去跟没返回去不就一样了么!

因此,我们只需要在进入首页(假设地址是 localhost:8080/home)时,往 history 里再加入一条首页记录,不就好了嘛!

代码:

function closeWXWindow() {
  // TODO: 关闭微信浏览器
}

onMounted(() => {
  /** 新增内容 begin👇*/ 
  const state = {
    title: 'title',
    url: '#',
  };
  // 往 history 里新加了一条 “localhost:8080/home/#” 记录
  // “#” 其实就是当前页的意思,有这个符号跟没有一样
  window.history.pushState(state, 'title', '#'); 
  /** 新增内容 end👆*/

  window.addEventListener('popstate', closeWXWindow);
});

// 记得离开该页面时取消监听,否则在其他页面按返回键也会直接关闭浏览器了~
onUnmounted(() => {
  window.removeEventListener('popstate', closeWXWindow);
});

很棒,现在浏览器还是会返回“上一页”,但“上一页”其实还是首页,所以看起来就是:按返回键并没有返回上一页!目标达成!

3、然后执行自定义事件(关闭微信浏览器)

这个简单!使用微信开放接口 WeixinJSBridge 即可。

不需要任何引入,直接在代码里使用:

/** 关闭微信浏览器 */
function closeWXWindow() {
  // 微信浏览器里有一个 WeixinJSBridge 对象,就像普通浏览器里必有 window 对象一样,无需额外引入
  // 不过保险起见,还是判断一下是否为空
  if (WeixinJSBridge?.invoke) {
    WeixinJSBridge.invoke('closeWindow', {}, () => {
      console.error('关闭微信网页失败');
    });
  }
}

注:1)其他教程里有说用 "WeixinJSBridge.call('closeWindow', () => {...})" 的。但我实测该方法已经无效了。

2)如果项目使用了 ts,那会报 WeixinISBridge 未定义的错。记得在 xx.d.ts 文件中定义一下该变量:declare const WeixinJSBridge;

4、完整代码

/** 关闭微信浏览器 */
function closeWXWindow() {
  if (WeixinJSBridge?.invoke) {
    WeixinJSBridge.invoke('closeWindow', {}, () => {
      console.error('关闭微信网页失败');
    });
  }
}

// 拦截返回键。在首页返回时,应该直接关闭h5,避免回到重定向页面无限循环
onMounted(() => {
  const state = {
    title: 'title',
    url: '#',
  };
  window.history.pushState(state, 'title', '#');
  window.addEventListener('popstate', closeWXWindow);
});
onUnmounted(() => {
  window.removeEventListener('popstate', closeWXWindow);
});

四、补充

到这里已经完成了!

不过你是否注意到我在“一、背景”的第一行标了一个加粗: location.replace(xxx) 或 location.href = xxx ?

是这样的,我的这个“首页”其实是指 vue-router 中的首页,不是浏览器history中的首页。如果是要监控 vue-router 中非首页的返回,其实可以不监听 popstate 事件,而是用 vue-router 中的 onBeforeRouteLeave 钩子。该钩子在离开当前路由页前被调用。

代码:

/** 关闭微信浏览器 */
function closeWXWindow() {
  if (WeixinJSBridge?.invoke) {
    WeixinJSBridge.invoke('closeWindow', {}, () => {
      console.error('关闭微信网页失败');
    });
  }
}

onBeforeRouteLeave((to, from, next) => {
  closeWXWindow();
  next(false); // 阻止下一步操作,看起来就是“不返回上一级页面”
});

有不正确之处还望指出~

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值