CSS & JS Effect – Do something on enter/leave window tab
需求
我在做一个体验
当用户 submit enquiry 后会 window.open 开启 WhatsApp。而当用户关闭 WhatsApp 回来网站后,会 show 一个 feedback message。
实现思路
关键就在如何感知到,用户从 WhatsApp 切换回到了网站。
参考: Detect When Users Switch Tabs using JavaScript
监听 visibilitychange,然后通过 document.visibilityState 得知是 hidden or visible。
hidden 表示 leave tab,visible 表示 back to tab。
Android 鬼
本来是很简单的东西,但不知道是不是我手机的问题。Android 在开启 WhatsApp 的时候会触发 2 次。
Windows:open WhatsApp > hidden > close WhatsApp > visible
Android:open WhatsApp > hidden > visible > hidden > close WhatsApp > visible
显然 Windows 是正常的,Android 跑了多一次。
Workaround 就是尽可能判断出 Android 的情况,不要被它搞乱。我没有太认真去思考 right way,我觉得多半是一个 bug 来的,所以暂时解决就好了。
参考代码注释理解吧
const beforeWindowOpenTime = performance.now(); window.open(generateWhatsAppLink(whatsAppNumberBS.value, message), '_blank'); // note 解忧: // 这里有一个 user back from WhatsApp 后 show submitted feedback 的体验。 // 它比较复杂,因为手机有 bug, // 正常情况下 visibilitychange 会 dispatch when user leave/enter tab,离开 state = hidden,回来 state = visible。 // so when window open WhatsApp, dispatch lever tab 咯, when user close WhatsApp, dispatch enter tab 咯. // 但是我的 android 有鬼。 // when window open WhatsApp,它会先 leave + enter 1 次, 紧接着又 leave 1 次, 直到 user back // 所以下面代码需要顾虑它第一轮假的 leave + enter const [visible$, hidden$] = partition( fromEvent(window, 'visibilitychange').pipe(share()), () => document.visibilityState === 'visible', ); // 监听第一次 visible visible$.pipe(take(1)).subscribe(() => { const now = performance.now(); // 如果第一次 visible 超过 1 秒 if (now - beforeWindowOpenTime >= 1000) { // 直接 show feedback,因为 android 鬼是很快的,绝对不会超过 1 秒 showSubmittedFeedback(); return; } // 如果小于 1 秒,那可能是 android 鬼,或者 user 真的很快就 close WhatsApp // 我们尝试监听 hidden,如果是 android 鬼,那么 2 秒内会触发 hidden // 如果 2 秒后没有 hidden 那判定是 user close 很快。 hidden$.pipe(take(1), timeout({ first: 2000 })).subscribe({ next() { // android 鬼的话,等待下一次的 visible 表示 user close visible$.pipe(take(1)).subscribe(() => showSubmittedFeedback()); }, error() { // user close 的话,直接 show feedback showSubmittedFeedback(); }, }); function showSubmittedFeedback() { setTimeout(() => { submitFeedbackReCaptchaContainer.submitFeedbackReCaptchaContainerController.showSubmittedFeedback(); }, 1000); } });
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
2022-10-05 Google – Reviews
2021-10-05 Figma 学习笔记 – Auto Layout
2021-10-05 Figma 学习笔记 – Scroll and Position Fixed
2021-10-05 Figma 学习笔记 – Constraints 约束
2021-10-05 Figma 学习笔记 – Align 对齐
2021-10-05 Figma 学习笔记 – Border
2021-10-05 Figma 学习笔记 – Comment