滚动上报实现

  • 2019 年 12 月 4 日
  • 笔记

最近产品说要在一个课程卡片列表页面中收集用户滚动行为的数据,大致是要获取用户滚动列表后曝光过的课程卡片数据。

scroll

那还不简单,直接监听列表元素的scroll事件,然后上报呗:

$list.on('scroll', () => {    let itemHeight = $list.find('li').outerHeight(true);    let scrollTop = $list.scrollTop();    let count = Math.ceil(scrollTop/itemHeight);      // report count...  });

想必聪明的你一看就知道有点问题:

  • scroll事件触发的那么频繁,尽管加上节流也上报了很多次无用数据
  • 首屏的列表卡片曝光个数并没有上报,需要额外地手动触发一次scroll事件

beforeunload

为了避免不必要的上报,我想只在页面卸载的时候上报一次数据应该就可以了吧,于是我就尝试了beforeunload事件:

let maxCount = 0;    // scroll to change maxCount...    window.addEventListener('beforeunload', () => {    // report maxCount...  });

经过实践,在QQ客户端的内嵌页面可能长时间都不会关闭,上报点依旧不可控。

blur?

思前想后,还是在上报次数上折中,决定尝试失焦事件。

但是依据MDN的blur event文档,它是不冒泡的,而如果要在列表元素上监听焦点相关的事件,是需要在元素上增加tabIndex属性的,在个别浏览器的实现中,对于此种容器元素获取焦点会有边框特效,带来副作用,而且聚焦的范围也缩小了。

所以采用focusout事件是一个较为不错的选择:

let maxCount = 0;  let reportedCount;    // scroll to change maxCount...    $(document.body).on('focusout', () => {    if (maxCount > reportedCount) { // 只需上报最大值即可        // report maxCount...    }  });

focusout事件的兼容性还是不错的,因为此需求只需要在QQ内嵌页中完成,所以并没有考虑到firefox的兼容性,并且它是冒泡的。

总结

以上是本人在此需求点上的一些浅见,如果聪明的你有更好的实践或者方法的话欢迎指教~

作为前端开发者,系统性地学习DOM,加深对它的理解才更好地在业务实践中抉择。