taro
taro copied to clipboard
h5页面中使用路由守卫强制留在当前页面时,safari浏览器手势滑动返回上一页被拦截后回到当前页过程中会有3秒左右的卡顿
相关平台
H5
浏览器版本: safari15.4(iOS) 使用框架: React
复现步骤
- 安装taro/cli并使用cli创建工程,选择react工程(省略安装依赖等步骤说明)
- 在步骤1创建好的工程中添加两个页面,A、B,其中A页面中添加一个跳转到B页面的按钮
- 在B页面中增加 https://docs.taro.zone/docs/h5#%E8%B7%AF%E7%94%B1%E5%AE%88%E5%8D%AB 文档中提到的方法,对页面返回进行拦截,不做任何用户交互判断,直接阻止页面返回
- 启动项目,在iphone手机safari浏览器中打开A页面,
- 点击A页面中的按钮跳转到B页面
- 使用手势从B页面返回A页面
期望结果
页面停留在B页面
实际结果
会在A页面中有3秒左右的停留,再返回到B页面
补充说明
- 安卓手机同样的操作,不会卡顿(安卓手机没有类似ios的划动动画)
- 使用浏览器自带的按钮(左箭头)操作返回,也不会卡顿
环境信息
taro info
👽 Taro v3.5.3
Taro CLI 3.5.3 environment info:
System:
OS: macOS 11.6
Shell: 5.8 - /bin/zsh
Binaries:
Node: 14.18.1 - ~/.nvm/versions/node/v14.18.1/bin/node
Yarn: 1.22.17 - /opt/homebrew/bin/yarn
npm: 6.14.15 - ~/.nvm/versions/node/v14.18.1/bin/npm
npmPackages:
@tarojs/cli: 3.5.3 => 3.5.3
@tarojs/components: 3.5.3 => 3.5.3
@tarojs/helper: 3.5.3 => 3.5.3
@tarojs/plugin-framework-react: 3.5.3 => 3.5.3
@tarojs/plugin-platform-alipay: 3.5.3 => 3.5.3
@tarojs/plugin-platform-jd: 3.5.3 => 3.5.3
@tarojs/plugin-platform-qq: 3.5.3 => 3.5.3
@tarojs/plugin-platform-swan: 3.5.3 => 3.5.3
@tarojs/plugin-platform-tt: 3.5.3 => 3.5.3
@tarojs/plugin-platform-weapp: 3.5.3 => 3.5.3
@tarojs/react: 3.5.3 => 3.5.3
@tarojs/router: 3.5.3 => 3.5.3
@tarojs/runtime: 3.5.3 => 3.5.3
@tarojs/shared: 3.5.3 => 3.5.3
@tarojs/taro: 3.5.3 => 3.5.3
@tarojs/taro-h5: 3.5.3 => 3.5.3
@tarojs/webpack5-runner: 3.5.3 => 3.5.3
babel-preset-taro: 3.5.3 => 3.5.3
eslint-config-taro: 3.5.3 => 3.5.3
react: ^18.0.0 => 18.2.0
npmGlobalPackages:
typescript: 3.8.3
补充信息
该场景主要用来对页面返回进行拦截对用户进行挽留,展示弹窗,用户进行操作后再确定是返回上一页还是停留在当前页,目前的情况是,对页面返回操作进行拦截后,ios手势返回会有3秒左右的卡顿,用户体验极差
myTaro3APP-react.zip 这是一个最小化复现的工程
另外补充,使用create-react-app创建的react项目,使用react-router(v5.3.3)提供的Prompt进行同样的操作,没有卡顿,测试页面文件路径为: my-react-app/src/test.js my-react-app.zip
关掉动画试试
关掉动画试试
-
taro的路由动画是关闭的,配置如下图

-
safari的手势动画是系统自带的,无法关闭
明白你的意思了,这在 iOS 中确实是个问题,但由于系统原因这个问题并不能在框架层面被修复
唯一可以禁用返回上一页滑动的方法是打开通过打开新的标签页跳过返回(由于这是一个破坏性的方案,并不会集成到框架中,可以由开发者自行选择使用)
Hello~
这个问题由于客观原因不会被修复,如果没有更多的问题这个 issue 将在 7 天后被自动关闭。
如果您在这 7 天中更新更多信息自动关闭的流程会自动取消,如有其他问题也可以发起新的 Issue。
Good luck and happy coding~
明白你的意思了,这在 iOS 中确实是个问题,但由于系统原因这个问题并不能在框架层面被修复
唯一可以禁用返回上一页滑动的方法是打开通过打开新的标签页跳过返回(由于这是一个破坏性的方案,并不会集成到框架中,可以由开发者自行选择使用)
那我还有一个疑问哦,我这边使用create-react-app创建了项目,项目里面使用react-router(v5.3.3)的Prompt来实现同样的拦截效果,在ios端就不会出现类似的情况,滑动返回非常流畅 我也看了react-router的Prompt的源码(https://github.com/remix-run/react-router/blob/v5/packages/react-router/modules/Prompt.js) 里面的原理 跟你们在https://docs.taro.zone/docs/h5#%E8%B7%AF%E7%94%B1%E5%AE%88%E5%8D%AB 这个文档里提供的方法原理是一样的,都是通过history.js提供的block方法实现的
Hello~
这个问题由于客观原因不会被修复,如果没有更多的问题这个 issue 将在 7 天后被自动关闭。
如果您在这 7 天中更新更多信息自动关闭的流程会自动取消,如有其他问题也可以发起新的 Issue。
Good luck and happy coding~
那我还有一个疑问哦,我这边使用create-react-app创建了项目,项目里面使用react-router(v5.3.3)的Prompt来实现同样的拦截效果,在ios端就不会出现类似的情况,滑动返回非常流畅 我也看了react-router的Prompt的源码(https://github.com/remix-run/react-router/blob/v5/packages/react-router/modules/Prompt.js) 里面的原理 跟你们在https://docs.taro.zone/docs/h5#%E8%B7%AF%E7%94%B1%E5%AE%88%E5%8D%AB 这个文档里提供的方法原理是一样的,都是通过history.js提供的block方法实现的
拦截时机不一样吧,你也可以在相关的生命周期拦截试试
我们也尝试过用safari分析页面返回的时间线,发现这中间有2秒时间的空白,从safari浏览器中无法得知这2秒的空白发生了什么,B页面返回A页面,在safari中记录的时间线,如下图

那我还有一个疑问哦,我这边使用create-react-app创建了项目,项目里面使用react-router(v5.3.3)的Prompt来实现同样的拦截效果,在ios端就不会出现类似的情况,滑动返回非常流畅 我也看了react-router的Prompt的源码(https://github.com/remix-run/react-router/blob/v5/packages/react-router/modules/Prompt.js) 里面的原理 跟你们在https://docs.taro.zone/docs/h5#%E8%B7%AF%E7%94%B1%E5%AE%88%E5%8D%AB 这个文档里提供的方法原理是一样的,都是通过history.js提供的block方法实现的
拦截时机不一样吧,你也可以在相关的生命周期拦截试试
我在Taro3中也尝试了在wiillUnMount的时候做跟react-router一样的拦截操作,一样的会卡顿
unmount 事件不太会有用,卸载时路由变更应该还没有生效
useLoad、useReady 试过么🤔
这俩没有试过,我试一下
unmount 事件不太会有用,卸载时路由变更应该还没有生效
react-router就是在unmount的时候调用的哦,效果是对的呢
useLoad、useReady 试过么🤔
这俩没有试过,我试一下
我理解了一下,这俩不能实现我说的效果吧,离开当前页面的时候怎么可能会触发load和ready呢?
Hello~
这个问题由于客观原因不会被修复,如果没有更多的问题这个 issue 将在 7 天后被自动关闭。
如果您在这 7 天中更新更多信息自动关闭的流程会自动取消,如有其他问题也可以发起新的 Issue。
Good luck and happy coding~
react-router就是在unmount的时候调用的哦,效果是对的呢
路由的逻辑是有区别的,触发时机不一致不能一概而论(Taro 并不一定会在路由变更时触发 unmount 事件,实际上是也可能是 hide 事件)
我理解了一下,这俩不能实现我说的效果吧,离开当前页面的时候怎么可能会触发load和ready呢?
确实是,不过还有一个事件是早于 taro 触发 unmount 事件的,可以通过 history.listen 或者浏览器的 popstate 事件直接监听路由变更来判断
window.addEventListener('popstate', () => {
// TODO
})
history.listen(() => {
// TODO
})
Taro.eventCenter.on('__taroRouterChange', () => {
// TODO
})
react-router就是在unmount的时候调用的哦,效果是对的呢
路由的逻辑是有区别的,触发时机不一致不能一概而论(Taro 并不一定会在路由变更时触发 unmount 事件,实际上是也可能是 hide 事件)
我理解了一下,这俩不能实现我说的效果吧,离开当前页面的时候怎么可能会触发load和ready呢?
确实是,不过还有一个事件是早于 taro 触发 unmount 事件的,可以通过 history.listen 或者浏览器的 popstate 事件直接监听路由变更来判断
Taro1.x里面有一个生命周期是beforeRouteLeave,我看了这个里面的实现,是通过监听 popstate 来监听路由变化,再根据路由变化及用户操作确定是否进行拦截,那里边有同样的问题,因为框架版本较低才来拿最新版做实验,出了同样的问题才说要反馈下的
Taro1.x里面有一个生命周期是beforeRouteLeave,我看了这个里面的实现,是通过监听 popstate 来监听路由变化,再根据路由变化及用户操作确定是否进行拦截,那里边有同样的问题,因为框架版本较低才来拿最新版做实验,出了同样的问题才说要反馈下的
这个生命周期确实是应对与该情况,不过它是在 3.x 构建时新增的特性所以并未同步到最新版本,欢迎 PR~
Hello~
这个问题由于客观原因不会被修复,如果没有更多的问题这个 issue 将在 7 天后被自动关闭。
如果您在这 7 天中更新更多信息自动关闭的流程会自动取消,如有其他问题也可以发起新的 Issue。
Good luck and happy coding~
同样的写法使用原生react就不会卡顿,在使用taro 开发的版本上就会卡顿,至少证明这个问题是Taro 引入的,应该要解决掉才对吧?
同样的写法使用原生react就不会卡顿,在使用taro 开发的版本上就会卡顿,至少证明这个问题是Taro 引入的,应该要解决掉才对吧?
所以你那边是遇到了一样的问题吗?
我们也尝试过用safari分析页面返回的时间线,发现这中间有2秒时间的空白,从safari浏览器中无法得知这2秒的空白发生了什么,B页面返回A页面,在safari中记录的时间线,如下图
这个可以麻烦你们那边看下中间这个2s是干了啥吗?稳定复现哦
Hello~
这个问题由于客观原因不会被修复,如果没有更多的问题这个 issue 将在 7 天后被自动关闭。
如果您在这 7 天中更新更多信息自动关闭的流程会自动取消,如有其他问题也可以发起新的 Issue。
Good luck and happy coding~
这个可以麻烦你们那边看下中间这个2s是干了啥吗?稳定复现哦
并没有复现到该项,猜测由于页面是懒加载的等待加载完成造成的,可以先尝试用这些方法修复咯
window.addEventListener('popstate', () => { // TODO }) history.listen(() => { // TODO })
同样的写法使用原生react就不会卡顿,在使用taro 开发的版本上就会卡顿,至少证明这个问题是Taro 引入的,应该要解决掉才对吧?
所以你那边是遇到了一样的问题吗?
是的,一样的问题。
期望结果
页面停留在B页面
实际结果
会在A页面中有3秒左右的停留,再返回到B页面
补充信息
该场景主要用来对页面返回进行拦截对用户进行挽留,展示弹窗,用户进行操作后再确定是返回上一页还是停留在当前页,目前的情况是,对页面返回操作进行拦截后,ios手势返回会有3秒左右的卡顿,用户体验极差
更新一下信息,实际测试后并没有在 iOS 或者 mac 上的 safari 中未能复现到 3秒延迟问题(在 mac 中部分情况下有延迟)。
另外可以通过所示 demo ,可以发现在 chrome 中存在一些问题,即 retry 方法为生效,所以导致在 chrome 中取消路由守卫失效,可以使用 navigateTo 替换方案。
期望结果
页面停留在B页面
实际结果
会在A页面中有3秒左右的停留,再返回到B页面
补充信息
该场景主要用来对页面返回进行拦截对用户进行挽留,展示弹窗,用户进行操作后再确定是返回上一页还是停留在当前页,目前的情况是,对页面返回操作进行拦截后,ios手势返回会有3秒左右的卡顿,用户体验极差
更新一下信息,实际测试后并没有在 iOS 或者 mac 上的 safari 中未能复现到 3秒延迟问题(在 mac 中部分情况下有延迟)。
另外可以通过所示 demo ,可以发现在 chrome 中存在一些问题,即 retry 方法为生效,所以导致在 chrome 中取消路由守卫失效,可以使用 navigateTo 替换方案。
mac中的safari调试手机时没有手势,是无法复现问题的,需要在电脑上把工程跑起来,用手机safari访问,并使用手势返回,只有手势返回有问题
期望结果
页面停留在B页面
实际结果
会在A页面中有3秒左右的停留,再返回到B页面
补充信息
该场景主要用来对页面返回进行拦截对用户进行挽留,展示弹窗,用户进行操作后再确定是返回上一页还是停留在当前页,目前的情况是,对页面返回操作进行拦截后,ios手势返回会有3秒左右的卡顿,用户体验极差
更新一下信息,实际测试后并没有在 iOS 或者 mac 上的 safari 中未能复现到 3秒延迟问题(在 mac 中部分情况下有延迟)。
另外可以通过所示 demo ,可以发现在 chrome 中存在一些问题,即 retry 方法为生效,所以导致在 chrome 中取消路由守卫失效,可以使用 navigateTo 替换方案。
另外,navigateTo方法需要知道目标路由,并且是push一条记录,但是我们的场景是需要从当前页面返回上一个页面的时候做一些挽留操作,暂时阻止用户离开,用户确认后还是要返回上一页的,不是再push一个页面进来