如何实现元素曝光上报?

更新日期: 2019-08-07阅读: 2.3k标签: 元素

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


解决方案

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


方案一:监听页面或者区域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://segmentfault.com/a/1190000019980376


链接: https://fly63.com/article/detial/4550

使用原生js来控制、修改CSS伪元素的方法总汇, 例如:before和:after

在网页中,如果需要使用辅助性/装饰性的内容的时候,这就需要使用伪元素了。在使用伪元素的时候,会发现js并不真能直接控制它,这篇文章主要就介绍下如果间接的控制、修改css中伪元素的方法

CSS隐藏元素的五种方法

用css隐藏页面元素有许多种方法。1、opacity:0;2、visibility:hidden;3、diaplay:none;4、position:absolute;5、clip-path。大家可以根据具体情况选择适合的方法来隐藏元素

CSS隐藏页面元素常用方法_不同场景下使用CSS隐藏元素

使用 CSS 让元素不可见的方法很多,剪裁、定位到屏幕外、明度变化等都是可以的。虽然它们都是肉眼不可见,但背后却在多个维度上都有差别

js动态生成html元素并为元素追加属性

动态生成HTML元素的方法有三种:document.createElement()创建元素,再用appendChild( )添加、使用innerHTML直接将元素添加到指定节点、jQuery创建节点...

原生js删除元素

通过id删除;通过class获取元素;清空一个元素,即删除一个元素的所有子元素 ;原理很简单,就是不断的判断要清空的div还有没有子节点,有的话就删除一个子节点(这里是它的首个子节点),直到删除完毕为止。

原生JS如何获取当前元素属于父元素第几个子元素

我们经常通过document.getElementById 方法来获取到一个元素,这个时候我们经常需要有一个需求,那就是如何判断这个元素在父元素中的位置。原生JS有一个常见的小技巧那就是通过元素的previousSibling 属性,额外需要注意的是该属性会遍历text节点,即回车键。

在js中获取页面元素的属性值时,弱类型导致的诡异事件踩坑记录

前几天写一个js的时候遇到一个非常诡异的事情,这个问题是这样的,我要获取一个页面的DOM元素的val值,判断这个值是否比某个变量大,这个需求原先数字最大也就是10,现在要改了,可能会更多,这个时候我发现比较大小的判断就出了问题:

JS 创建元素的三种方法

动态创建元素一 document.write()body标签中就会插入但是这种方法几乎不用,因为这回影响页面的布局,甚至会将页面原来的内容冲刷掉,从而只显示输出内容;动态创建元素二 innerHTML

去除inline-block元素间的间距

真正意义上的inline-block水平呈现的元素间,换行显示或者空格隔开的情况下会有间距,这是因为浏览器在解析时,会将换行等读取成一个空格导致。

什么是可替换元素?

请问什么是可替换元素和非可替换元素,它们的差异是什么?并举例说明。前端面试中 HTML 的题目本来就最少,而且并不难,翻来覆去也就那几样。我们之前已经谈到过最经典的 HTML 语义化 ,今天就借此机会来谈谈可替换元素。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!