heatmap.js canvas悬停内容时不绘制 层级与事件监听冲突问题
heatmap.js 热力图遮挡交互/无法采集事件解决方案
浏览器默认事件响应规则是渲染层级更高的元素会优先拦截鼠标事件,反复调整z-index无法同时满足「热力图可见」「交互不被遮挡」「全页采集轨迹」三个需求,直接用CSS的pointer-events属性即可解决,不需要修改heatmap.js源码。
核心修复逻辑
- 热力图外层容器设置最高
z-index,固定定位铺满整个视口,保证热力图始终渲染在所有业务内容上方,不会被遮挡 - 给热力图外层容器添加
pointer-events: none,该属性会让容器及内部canvas完全不接收任何鼠标/指针事件,所有点击、文本选中、悬停交互会直接穿透热力图层,落到下层业务元素上 - 鼠标移动、点击事件不要绑定在热力图容器上,直接绑定到
document全局对象,坐标使用相对视口的clientX/clientY,避免多层元素嵌套导致的坐标计算偏移
修正后完整代码
CSS 部分
body { position: relative; width: 100%; height: auto; margin: 0; } /* 热力图容器:固定铺满视口,最高层,事件穿透 */ .wrapper { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 9999; pointer-events: none; /* 核心配置:不拦截任何事件 */ } .wrapper #heatmap { width: 100%; height: 100%; } /* 业务内容不需要调整z-index,正常排版即可 */ .content { position: relative; padding: 24px; }
JavaScript 部分
const heatmapInstance = h337.create({ container: document.querySelector('#heatmap'), radius: 30 }); // 全局绑定鼠标移动事件,采集轨迹 document.addEventListener('mousemove', (ev) => { heatmapInstance.addData({ x: ev.clientX, y: ev.clientY, value: 1 }); }); // 全局绑定点击事件,点击点位权重设更高 document.addEventListener('click', (ev) => { heatmapInstance.addData({ x: ev.clientX, y: ev.clientY, value: 5 }); });
HTML 部分
<script src="https://cdn.jsdelivr.net/npm/heatmapjs@2.0.2/heatmap.min.js"></script> <body> <!-- 业务内容正常放在DOM流中,不需要调整层级 --> <div class="content"> <button>Click me!</button> <p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Consequatur animi ipsum fugit quibusdam excepturi quidem sequi vitae, dolor dignissimos ad rerum neque nam itaque illo perspiciatis eligendi, deserunt repellat in?</p> <p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Consequatur animi ipsum fugit quibusdam excepturi quidem sequi vitae, dolor dignissimos ad rerum neque nam itaque illo perspiciatis eligendi, deserunt repellat in?</p> <p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Consequatur animi ipsum fugit quibusdam excepturi quidem sequi vitae, dolor dignissimos ad rerum neque nam itaque illo perspiciatis eligendi, deserunt repellat in?</p> </div> <!-- 热力图容器放在DOM靠后位置,配合高z-index铺在最上层 --> <div class="wrapper"> <div id="heatmap"></div> </div> </body>
注意事项
- 不需要给任何业务元素单独设置z-index,只要热力图容器配置了
pointer-events: none,哪怕层级最高也不会挡住任何交互 - 不要用
position: absolute定位热力图容器,用position: fixed配合100vw/100vh可以避免页面滚动时热力图和内容错位 - 禁止使用
layerX/layerY、offsetX/offsetY计算坐标,这两个值会随事件触发的目标元素变化,很容易出现点位偏移 - 如果需要临时隐藏热力图,直接切换
.wrapper的display属性即可,隐藏时可以暂时解绑事件监听降低性能消耗
内容的提问来源于stack exchange,提问作者Killick
相关产品推荐
相关产品推荐

