首先介绍一下想要写下这篇文章的原因(只想看坑的可以跳过这一段):前段时间接到了一个需求,大致是希望记录用户在某个页面的操作时间(没有太高的精度要求)。我们的项目是一个后台管理项目,使用Vue制作的一个单页应用,那么首先用户进入页面肯定是知道的,页面组件的created生命周期开始计一个时间戳(还有很多种其他方法),那么如何得知用户离开页面呢?首先需要考虑的是有几种算作离开页面的方式:
- 1.用户通过a标签跳转到同域名下的其他路由
- 2.用户最小化或者打开着去看其他页面了,这种情况我们的PM定义为未离开,可以不处理
- 3.用户进行了前进、后退(刷新较为特殊,放在下面一条里)
以上三种情况,这里面会用到vue-router的导航守卫相关api以及组件的卸载周期来记录,需要考虑两种方式同时触发(肯定有先后)时的处理,和主旨无关,这里不展开了
- 4.用户关闭了页面(刷新、跳转去其他域名、关闭浏览器页面标签、关闭整个浏览器等一切视为页面关闭的情况)
这种情况就需要用到咱们的主角了:监听beforeonload事件
那么首先来看一下这个事件的用法,可以使用addEventListener或者直接window.onbeforeunload = func,那么这时候第一个分歧就来了
1.使用onbeforeunload:如果保证你的项目只有你使用了一个这种事件,那么ok,取消监听也很方便,onbeforeunload = null即可。缺点当然是扩展性差。
2.使用addEventListener:首先,你很可能需要取消这个事件的监听,那么你需要保证add时候和remove时候传参的函数是同一个函数(在内存中的位置是一样的)
还有就是两种方式在做提示的时候默认文案修改的方式是不同的(计时这种用户无感知的行为不用管)on的方法直接return文案即可,addEventListener则需要修改event.returnValue
第一个分歧解决之后,首先要看一下这个事件的兼容性(不是应该先看兼容性吗!)
嗯很好,要啥自行车,由于我的项目使用人群可控,这个问题不用考虑。
接下来就要看一下这个事件能否满足咱们的需求了:希望在这个事件中调用一个ajax接口让后台记录
测试方法:在关闭页面时候,接口调用记录和控制台中打印出的东西无法看到,在这个函数中alert也是不起作用的,那么只能是麻烦后端看一下日志,结果是看到了调用记录,证明是可行的(当时松了一口气)。不过这种方法只适用于对精度不是很高的情况下(网络波动等可能造成后端无法拿到数据,极少情况)。
到此看来仿佛已经完成了这个需求,在代码完成后自己测试了一下,ok没有问题!
然而,经验丰富的QA同学提出:如果在任务管理器中alt+e(结束进程)来关闭浏览器,还能否成功计时呢?
测试了一下,日志中莫得反映。。。。。。
没错,beforeunload这个事件不适用于浏览器意外关闭的情况(进程被杀),也就是说意外断电等情况是无法记录的,由于pm认为这种情况暂时不需要处理(较低精确度),所以就暂时还是使用这种方法进行记录。
引出思考:如果说精度较高,这种情况该如何处理呢?可以考虑定时调用接口记录(那么用户实际操作次数的精度也需要考虑,需要让后端在统计时得知哪几次调用其实是应该合并的),也可以考虑websoket(和第一种方法其实思路一样)
总结:利用beforeunload进行计时打点时,适用于低精度的需求情景下,更多时候它还是适合用于提示用户是否已经保存表单的场景。