小编给大家分享一下js实现元素曝光上报的示例,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!
进行数据上报的时候,经常会遇到列表数据曝光上报的问题,只对在当前可视范围内的数据内容进行曝光上报,而对于未在可视范围内的数据不进行曝光上报,等待用户滚动页面或者区域使元素出现在可视范围内时才进行曝光上报。
解决方案
目前针对此类问题,主要有两种解决方案。
方案一:监听页面或者区域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)
看完了这篇文章,相信你对“js实现元素曝光上报的示例”有了一定的了解,如果想了解更多相关知识,欢迎关注天达云行业资讯频道,感谢各位的阅读!