资讯专栏INFORMATION COLUMN

如何实现元素曝光上报

VincentFF / 2874人阅读

摘要:进行数据上报的时候,经常会遇到列表数据曝光上报的问题,只对在当前可视范围内的数据内容进行曝光上报,而对于未在可视范围内的数据不进行曝光上报,等待用户滚动页面或者区域使元素出现在可视范围内时才进行曝光上报。

进行数据上报的时候,经常会遇到列表数据曝光上报的问题,只对在当前可视范围内的数据内容进行曝光上报,而对于未在可视范围内的数据不进行曝光上报,等待用户滚动页面或者区域使元素出现在可视范围内时才进行曝光上报。

解决方案

目前针对此类问题,主要有两种解决方案。

方案一:监听页面或者区域scroll事件,通过getBoundingClientRect接口取元素的位置与可视窗口进行判断。
function isElementInViewport(el) {
    var rect = el.getBoundingClientRect();

    var width_st = rect.width / 2,
        height_st = rect.height / 2;

    var innerHeight = window.innerHeight,
        innerWidth  = window.innerWidth;


    if (   rect.top <=0 && rect.height > innerHeight 
        || rect.left <= 0 && rect.width > innerWidth
    ) {
        return rect.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  ) )
    );
}

var nodes = document.querySelectorAll(".item")
function report(node) {
    // 上报的逻辑
}
window.onscroll = function() {
    nodes.forEach(node => {
        if( isElementInViewport(node) ) {
            report(node)
        }
    })
    
}

优点:兼容性好
缺点:

需要关注页面或者区域的scroll事件

频繁的scroll事件,性能问题

方案二:通过 IntersectionObserver 监听元素是否处于可视范围
function report(node) {
    // 上报的逻辑
}
var intersectionObserver = new IntersectionObserver(entries => {
    entries.forEach(entry => {
        if( entry.intersectionRatio > 0 ) {
            report(entry.target)
        }
    })
})
var nodes = document.querySelectorAll(".item")
nodes.forEach(node => {
    intersectionObserver.observe(node)
})

优点:

无须关注 scroll

回调是异步触发,不会频繁触发,性能好

缺点:兼容性不好?

实际上,针对兼容性问题,w3c 官方提供了对应 polyfill, 因此intersectionObserver用于生产是可行的。

总结

笔者在实际运用中,通过 IntersectionObserver 封装了一个简单的调用库,应用于可视化埋点 sdk 中,用于解决元素曝光问题,如下

require("intersection-observer"); // polyfill

class Exposure {
    constructor(callback) {
        if (!callback || typeof callback !== "function") {
            throw new Error("need callback or selector param")
            return
        }
        this.intersectionObserver = new IntersectionObserver((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
        }
        let nodes = []
        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 ) {
            return false
        }
        if( typeof HTMLElement === "object" ) {
            return obj instanceof HTMLElement
        }
        if( typeof obj === "object"  && obj.nodeType === 1 && typeof obj.nodeName === "string" ) {
            return true
        }
        return false
    }
}

export default  Exposure

调用方法:

function report() {}
var exposurer = new Exposure((node) => {
    report(node)
})
exposurer.observe(".item)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106422.html

相关文章

  • 如何通过Vue自定义指令实现前端埋点详析

      获取用户的交互习惯及喜好,进一步提升转化率,可以在之前的埋点方案实现中,都是在具体的按钮或者图片被点击或者被曝光时主动通过事件去上报埋点。但这种方法适合在埋点比较少时还行的项目,遇见项目中需要大量埋点时,添加的代码就太多了,就会埋点逻辑与业务逻辑的高耦合。  由此需要换种方式。我先给大家普及下埋点上报方式都有哪些?  手动埋点  可视化埋点  无痕埋点  手动埋点,顾名思义就是纯手动写代码,调...

    3403771864 评论0 收藏0
  • 列表页曝光埋点实现

    摘要:列表页曝光埋点实现以商品为例要求商品一半以上出现在视窗中时上报该行的商品快速滑动过去的商品不上报滑动过程中如果一行商品一直未消失在视野中一半以上,不能重复上报滑出视野的商品,再次滑入视野时需要再次上报分析需要以下信息商品所在行的高度固定值商 列表页曝光埋点实现 以商品为例 要求 商品一半以上出现在视窗中时 上报该行的商品 快速滑动过去的商品不上报 滑动过程中如果一行商品一直未消失在视...

    miqt 评论0 收藏0
  • 列表页曝光埋点实现

    摘要:列表页曝光埋点实现以商品为例要求商品一半以上出现在视窗中时上报该行的商品快速滑动过去的商品不上报滑动过程中如果一行商品一直未消失在视野中一半以上,不能重复上报滑出视野的商品,再次滑入视野时需要再次上报分析需要以下信息商品所在行的高度固定值商 列表页曝光埋点实现 以商品为例 要求 商品一半以上出现在视窗中时 上报该行的商品 快速滑动过去的商品不上报 滑动过程中如果一行商品一直未消失在视...

    pf_miles 评论0 收藏0
  • 广告的发展趋势和其中的前端角色

    摘要:本文借助发布的数字营销趋势报告,从广告的发展趋势和尚存问题讲起,引出前端开发在未来应该逐渐的所处的角色和应该承担的责任。总结本文描述了广告在年的发展趋势和当前存在的问题,并在广告的渲染,监测和上报上阐述了前端可以努力的方向。 上个周写个篇文章《一篇文章了解广告全链路》,在其中我们讨论了数字营销中广告是如何售卖的,以及广告的实时竞价和库存算法。但是,其实上面那篇文章还没有完结,它还缺了一...

    leon 评论0 收藏0
  • 页面跳转时,点击上报丢失问题解析

    摘要:背景最近在工作中,遇到了页面跳转时点击上报丢失的问题,突出表现在微信的上,上报后直接跳转的失败率达到了惊人的。对这三种失效的方案有兴趣的可以看页面跳转时,统计数据丢失问题探讨把要跳转的放到中,然后在下一个页面上上报点击。 背景 最近在工作中,遇到了页面跳转时点击上报丢失的问题,突出表现在微信ios的webview上,上报后直接跳转的失败率达到了惊人的93%。喝口水压压惊,开始逐步分析问...

    Bmob 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<