js如何实现元素曝光上报
进行数据上报的时候,经常会遇到列表数据曝光上报的问题,只对在当前可视范围内的数据内容进行曝光上报,而对于未在可视范围内的数据不进行曝光上报,等待用户滚动页面或者区域使元素出现在可视范围内时才进行曝光上报。
解决方案
目前针对此类问题,主要有两种解决方案。
方案一:监听页面或者区域scroll事件,通过getBoundingClientRect接口取元素的位置与可视窗口进行判断。
functionisElementInViewport(el){ varrect=el.getBoundingClientRect(); varwidth_st=rect.width/2, height_st=rect.height/2; varinnerHeight=window.innerHeight, innerWidth=window.innerWidth; if(rect.top<=0&&rect.height>innerHeight ||rect.left<=0&&rect.width>innerWidth ){ returnrect.left*rect.right<=0 ||rect.top*rect.bottom<=0 } return( rect.height>0 &&rect.width>0 &&((rect.top>=0&&rect.top<=innerHeight-height_st) ||(rect.bottom>=height_st&&rect.bottom<=innerHeight)) &&((rect.left>=0&&rect.left<=innerWidth-width_st) ||(rect.right>=width_st&&rect.right<=innerWidth)) ); } varnodes=document.querySelectorAll(".item") functionreport(node){ //上报的逻辑 } window.onscroll=function(){ nodes.forEach(node=>{ if(isElementInViewport(node)){ report(node) } }) }
优点:兼容性好
缺点:
- 需要关注页面或者区域的scroll事件
- 频繁的scroll事件,性能问题
方案二:通过IntersectionObserver监听元素是否处于可视范围
functionreport(node){ //上报的逻辑 } varintersectionObserver=newIntersectionObserver(entries=>{ entries.forEach(entry=>{ if(entry.intersectionRatio>0){ report(entry.target) } }) }) varnodes=document.querySelectorAll(".item") nodes.forEach(node=>{ intersectionObserver.observe(node) })
优点:
- 无须关注scroll
- 回调是异步触发,不会频繁触发,性能好
缺点:兼容性不好?
实际上,针对兼容性问题,w3c官方提供了对应polyfill,因此intersectionObserver用于生产是可行的。
总结
笔者在实际运用中,通过IntersectionObserver封装了一个简单的调用库,应用于可视化埋点sdk中,用于解决元素曝光问题,如下
require('intersection-observer');//polyfill classExposure{ constructor(callback){ if(!callback||typeofcallback!=='function'){ thrownewError("needcallbackorselectorparam") return } this.intersectionObserver=newIntersectionObserver((entries)=>{ entries.forEach(item=>{ if(item.intersectionRatio>0){ if(item.target){ callback(item.target,item) this.intersectionObserver.unobserve(item.target) } } }) }); } observe(selector,ignoreExposured){ if(!this.intersectionObserver||!selector){ return } letnodes=[] if(this.isDOM(selector)){//dom节点 nodes=[selector] }else{//选择器 nodes=document.querySelectorAll(selector) } if(!nodes.length){ return } nodes.forEach(node=>{ if(!ignoreExposured&&node.__wg__tracker__exposured__){ return } node.__wg__tracker__exposured__=true //开始观察 this.intersectionObserver.observe( node ); }) } disconnect(){ if(!this.intersectionObserver){ return } this.intersectionObserver.disconnect() } isDOM(obj){ if(!obj){ returnfalse } if(typeofHTMLElement==='object'){ returnobjinstanceofHTMLElement } if(typeofobj==='object'&&obj.nodeType===1&&typeofobj.nodeName==='string'){ returntrue } returnfalse } } exportdefaultExposure
调用方法:
functionreport(){} varexposurer=newExposure((node)=>{ report(node) }) exposurer.observe(".item)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。