js如何实现元素曝光上报


Posted in Javascript onAugust 07, 2019

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

解决方案

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

方案一:监听页面或者区域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)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jquery post方式传递多个参数值后台以数组的方式进行接收
Jan 11 Javascript
JS特效实现图片自动播放并可控的效果
Jul 31 Javascript
javascript定义类和类的实现实例详解
Dec 01 Javascript
DropDownList控件绑定数据源的三种方法
Dec 24 Javascript
jQuery插件zTree实现删除树子节点的方法示例
Mar 08 Javascript
前端跨域的几种解决方式总结(推荐)
Aug 16 Javascript
node+express+ejs使用模版引擎做的一个示例demo
Sep 18 Javascript
js实现鼠标移动到图片产生遮罩效果
Oct 21 Javascript
vue2.0 axios跨域并渲染的问题解决方法
Mar 08 Javascript
详解关于表格合并span-method方法的补充(表格数据由后台动态返回)
May 21 Javascript
ECharts地图绘制和钻取简易接口详解
Jul 12 Javascript
BootStrap前端框架使用方法详解
Feb 26 Javascript
详解Element-UI中上传的文件前端处理
Aug 07 #Javascript
element-ui中Table表格省市区合并单元格的方法实现
Aug 07 #Javascript
Vue+Typescript中在Vue上挂载axios使用时报错问题
Aug 07 #Javascript
更优雅的微信小程序骨架屏实现详解
Aug 07 #Javascript
vue 集成jTopo 处理方法
Aug 07 #Javascript
vue 集成 vis-network 实现网络拓扑图的方法
Aug 07 #Javascript
弱类型语言javascript开发中的一些坑实例小结【变量、函数、数组、对象、作用域等】
Aug 07 #Javascript
You might like
PHP文件下载类
2006/12/06 PHP
php+jQuery.uploadify实现文件上传教程
2014/12/26 PHP
php eval函数一句话木马代码
2015/05/21 PHP
php设计模式之工厂模式用法经典实例分析
2019/09/20 PHP
jQuery 获取、设置HTML或TEXT内容的两种方法
2014/05/23 Javascript
MVC Ajax Helper或Jquery异步加载部分视图
2015/11/29 Javascript
JavaScript蒙板(model)功能的简单实现代码
2016/08/04 Javascript
AngularJS入门教程之过滤器用法示例
2016/11/02 Javascript
微信小程序实现图片自适应(支持多图)
2017/01/25 Javascript
nodejs入门教程二:创建一个简单应用示例
2017/04/24 NodeJs
关于定制FileField中的上传文件名称问题
2017/08/22 Javascript
vue使用mint-ui实现下拉刷新和无限滚动的示例代码
2017/11/06 Javascript
vue 实现的树形菜的实例代码
2018/03/19 Javascript
JS字符串与二进制的相互转化实例代码详解
2019/06/28 Javascript
解决layer弹出层自适应页面大小的问题
2019/09/16 Javascript
Vue 实现创建全局组件,并且使用Vue.use() 载入方式
2020/08/11 Javascript
Nuxt 项目性能优化调研分析
2020/11/07 Javascript
VUE-ElementUI 自定义Loading图操作
2020/11/11 Javascript
用vite搭建vue3应用的实现方法
2021/02/22 Vue.js
[01:37]PWL S2开团时刻DAY1&2——这符有毒
2020/11/20 DOTA
Python绘制3d螺旋曲线图实例代码
2017/12/20 Python
Django进阶之CSRF的解决
2018/08/01 Python
python+webdriver自动化环境搭建步骤详解
2019/06/03 Python
python实现差分隐私Laplace机制详解
2019/11/25 Python
Can a struct inherit from another struct? (结构体能继承结构体吗)
2016/09/25 面试题
个人找工作的自我评价
2013/10/17 职场文书
超市营业员岗位职责
2013/12/20 职场文书
机械专业求职信范文
2014/07/15 职场文书
员工工作自我评价
2014/09/26 职场文书
2014年十八届四中全会思想汇报范文
2014/10/17 职场文书
2015年护士医德医风自我评价
2015/03/03 职场文书
护士自荐信范文
2015/03/25 职场文书
pytorch 权重weight 与 梯度grad 可视化操作
2021/06/05 Python
vue3获取当前路由地址
2022/02/18 Vue.js
Python Flask实现进度条
2022/05/11 Python
nginx 添加http_stub_status_module模块
2022/05/25 Servers