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 相关文章推荐
js综合应用实例简单的表格统计
Sep 03 Javascript
Jquery解析json数据详解
Dec 26 Javascript
JavaScript自定义日期格式化函数详细解析
Jan 14 Javascript
javascript验证邮件地址和MX记录的方法
Jun 16 Javascript
Jquery插件仿百度搜索关键字自动匹配功能
May 11 Javascript
微信小程序 两种滑动方式(横向滑动,竖向滑动)详细及实例代码
Jan 13 Javascript
jQuery实现选项卡功能(两种方法)
Mar 08 Javascript
微信小程序 http请求的session管理
Jun 07 Javascript
Vue唯一可以更改vuex实例中state数据状态的属性对象Mutation的讲解
Jan 18 Javascript
详解在网页上通过JS实现文本的语音朗读
Mar 28 Javascript
vue源码中的检测方法的实现
Sep 26 Javascript
vue.js click点击事件获取当前元素对象的操作
Aug 07 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 xml实例 留言本
2009/03/20 PHP
ThinkPHP中关联查询实例
2014/12/02 PHP
php使用cookie实现记住用户名和密码实现代码
2015/04/27 PHP
PHP实现微信提现功能(微信商城)
2019/11/21 PHP
javascript 全角转换实现代码
2009/07/17 Javascript
javascript类型转换示例
2014/04/29 Javascript
JavaScript数据类型详解
2015/04/01 Javascript
jQuery实现带有动画效果的回到顶部和底部代码
2015/11/04 Javascript
使用jquery获取url及url参数的简单实例
2016/06/14 Javascript
bootstrap datepicker 与bootstrapValidator同时使用时选择日期后无法正常触发校验的解决思路
2016/09/28 Javascript
jQuery实现简单的滑动导航代码(移动端)
2017/05/22 jQuery
koa router 多文件引入的方法示例
2019/05/22 Javascript
vue监听用户输入和点击功能
2019/09/27 Javascript
Vue-cli3生成的Vue项目加载Mxgraph方法示例
2020/05/31 Javascript
vue.js实现照片放大功能
2020/06/23 Javascript
详谈Vue.js框架下main.js,App.vue,page/index.vue之间的区别
2020/08/12 Javascript
详解JavaScript 的执行机制
2020/09/18 Javascript
浅析我对JS延迟异步脚本的思考
2020/10/12 Javascript
jQuery使用hide()、toggle()函数实现相机品牌展示隐藏功能
2021/01/29 jQuery
python正则分组的应用
2013/11/10 Python
python 实时得到cpu和内存的使用情况方法
2018/06/11 Python
Python数据类型之Set集合实例详解
2019/05/07 Python
django 实现celery动态设置周期任务执行时间
2019/11/19 Python
节日快乐! Python画一棵圣诞树送给你
2019/12/24 Python
Python matplotlib修改默认字体的操作
2020/03/05 Python
荷兰皇家航空公司官方网站:KLM Royal Dutch Airlines
2017/12/07 全球购物
Crocs波兰官方商店:女鞋、男鞋、童鞋、洞洞鞋
2019/10/08 全球购物
ellesse美国官方商店:意大利高级运动服品牌
2019/10/29 全球购物
高三地理教学反思
2014/01/11 职场文书
大学生的自我鉴定范文
2014/01/21 职场文书
2014年移动公司工作总结
2014/12/08 职场文书
爱心捐款感谢信
2015/01/20 职场文书
2015年五一劳动节演讲稿
2015/03/18 职场文书
党员身份证明材料
2015/06/19 职场文书
演讲稿之我的初心我的成长
2019/08/12 职场文书
教你用Python matplotlib库制作简单的动画
2021/06/11 Python