市面上的页面热力图大多数通过简单的基于点击 XY 坐标轴进行统计并展示, 只能统计点击的坐标, 不同的分辨率和网站布局方式 (居中等) 都会导致结果的不准确, 并不能正确的展示被点击的元素, 在页面进行改版或者布局改变时展示错误的热力图, 会给行为分析提供错误的信息.
例如下面的两张图:
图 1
图 2
图 1 与图 2, 他们相对浏览器的 XY 坐标相同, 但是他们一个行为是关掉弹框, 另外一个行为是点击 banner 图, 假设一个用户点击了弹框的关闭按钮, 并点击了 banner 图, 这样两次点击会在作为热力图展示时在 X:800 Y:260 的点上显示被点击两次, 但是你没有办法分辨到底是 banner 被点击两次还是弹框被关闭两次, 因为他们可能忽略了被点击的坐标点的 dom 层级及遮挡或者隐藏.
解决办法:
1, 统计上报
在页面被点击时获取当前事件源的 dom, 并获取当前的点击相对于事件源的 dom 的 XY 坐标,
比如, 当前页面结构为 html -> body -> div#App -> div.container -> div.close. 当 div.close 被点击时, 我们获取到 div.close 这个元素, 或获取到相对于 div.close 这个元素左上角的 XY 坐标, 假设为 X:0,Y:0. 这里就涉及到了, 怎样在展示的时候选取到当前点击的这个元素, 我们可以通过 Chrome-dompath 库提供的方法, 获取到当前这个 div.close 的 JS path, 类似于 Chrome devtools 里面的 element -> copy -> JS path. 这样 div.close 被点击时 我们需要记录两个数据, 第一个是当前元素的 JS path, 也就是 HTML -> body -> div#App -> div.container -> div.close, 第二个就是相对于 div.close 这个元素的左上角的 XY 坐标, 0,0.
2, 渲染展示
有了之前上报的数据, 在需要展示时, 通过浏览器打开要查看热力图的页面(这里为了环境一致, 最好就是直接在浏览器通过真实的线上地址打开页面), 在页面的基础上进行展示.
拿到 JS path(HTML -> body -> div#App -> div.container -> div.close, XY 坐标 (0,0), 我们首先通过 document.querySelector(JS path) 查看是否能获取到之前被点击的这个元素, 不存在的原因可能有
1)布局被改变导致元素结构不正确
2)当前 JS path 与统计上报时不一致
3)或者该元素为动态渲染, 当前并没有被渲染出来
通过 JS path 找不到 dom 主要包括但并不限于以上三种情况. 但是任何通过 JS path 找不到 dom 的情况 我们都可以直接不渲染, 这样我们可以保证最基本的原则, 不会提供错误的信息.
在获取到正确的被点击 dom 之后, 我们首先获取当前 dom 的宽高, 假如该 dom 宽高有一项为 0 则可以直接不展示, 因为该元素并没有真实展示在当前的页面上.
接下来获取该 dom 相对于浏览器的 XY 坐标. 根据当前我们浏览器可视窗口的大小, 我们判断该 dom 是否在可视窗口之外. 假如在可视窗口之外, 我们也直接不展示.
该 dom 在可视窗口之内, 我们要验证该 dom 是否被隐藏, 或者被其他元素遮挡, 也就是避免 dom 上方有弹框或者其他场景遮挡, 比如目标 dom 在一个自定义的 scroll 的 box 里面, 而且已经被滑动到不可见的区域. 这时候我们将目标 dom 与目标 dom 相对于浏览器的 XY 坐标使用 document.elementFromPoint(x, y)返回的元素进行对比, 查看通过 document.elementFromPoint(x, y)选取的元素是否为目标 dom. 假如为目标 dom 则判断该 dom 是展示在当前页面的最上层. 否则反之, 该元素已经被遮挡或者不可见.
最后该 dom 处于当前页面视图可见并在最上层时, 我们通过该元素相对于浏览器的 XY 坐标. 加上我们之间记录的点击时相对于目标 dom 左上角的 XY 坐标的偏移就是真实被点击的位置.
这样我们就可以愉快的展示正确的点击热力图.
优点:
该方法能正确展示点击热力图, 做到不提供错误信息.
缺点:
为了准确性, 进行展示时需要通过 JS path 获取 dom 进行对比等一系列操作, 所以使用与用户一致的真实场景. 目前我实现是使用浏览器插件对真实页面进行 JS 注入并展示, 另外的实现办法目前想到的是 也可以直接用 electron 通过渲染进程打开真实场景并注入 JS.
JS path 太长, 而且太细化, 导致数据很大. 在渲染时性能有一定影响.(待优化)
第一次写博客, 不足之处欢迎指正.
来源: http://www.jianshu.com/p/4ede9f22c97a