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 相关文章推荐
Mozilla中显示textarea中选择的文字
Sep 07 Javascript
Jquery 获取指定标签的对象及属性的设置与移除
May 29 Javascript
Javascript常用小技巧汇总
Jun 24 Javascript
详解JavaScript基于面向对象之创建对象(1)
Dec 10 Javascript
在AngularJS框架中处理数据建模的方式解析
Mar 05 Javascript
基于JavaScript实现 网页切出 网站title变化代码
Apr 03 Javascript
利用jQuery实现打字机字幕效果实例代码
Sep 02 Javascript
了解VUE的render函数的使用
Jun 08 Javascript
微信小程序中button组件的边框设置的实例详解
Sep 27 Javascript
Vue 2.0入门基础知识之内部指令详解
Oct 15 Javascript
Vue 实现分页与输入框关键字筛选功能
Jan 02 Javascript
Vue用mixin合并重复代码的实现
Nov 27 Vue.js
详解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
Protoss热键控制
2020/03/14 星际争霸
透析PHP的配置文件php.ini
2006/10/09 PHP
Laravel中扩展Memcached缓存驱动实现使用阿里云OCS缓存
2015/02/10 PHP
php版微信开发Token验证失败或请求URL超时问题的解决方法
2016/09/23 PHP
Laravel接收前端ajax传来的数据的实例代码
2017/07/20 PHP
JavaScript 事件对象介绍
2015/04/13 Javascript
jQuery实现返回顶部效果的方法
2015/05/29 Javascript
JS HTML5拖拽上传图片预览
2016/07/18 Javascript
Javascript之面向对象--方法
2016/12/02 Javascript
详解handlebars+require基本使用方法
2016/12/21 Javascript
原生js实现返回顶部缓冲效果
2017/01/18 Javascript
Vue.js开发环境快速搭建教程
2017/03/17 Javascript
js和jQuery以及easyui实现对下拉框的指定赋值方法
2018/01/23 jQuery
AngularJS修改model值时,显示内容不变的实例
2018/09/13 Javascript
ExtJs使用自定义插件动态保存表头配置(隐藏或显示)
2018/09/25 Javascript
微信小程序实现评论功能
2018/11/28 Javascript
在微信小程序中使用图表的方法示例
2019/04/25 Javascript
Layui数据表格判断编辑输入的值,是否为我需要的类型详解
2019/10/26 Javascript
vue 实现setInterval 创建和销毁实例
2020/07/21 Javascript
python3批量删除豆瓣分组下的好友的实现代码
2016/06/07 Python
使用Turtle画正螺旋线的方法
2017/09/22 Python
Python基于更相减损术实现求解最大公约数的方法
2018/04/04 Python
Python 编码规范(Google Python Style Guide)
2018/05/05 Python
django认证系统 Authentication使用详解
2019/07/22 Python
Python制作简易版小工具之计算天数的实现思路
2020/02/13 Python
python批量处理多DNS多域名的nslookup解析实现
2020/06/28 Python
Html5如何唤起百度地图App的方法
2019/01/27 HTML / CSS
美国时尚假发购物网站:Wigsbuy
2019/04/06 全球购物
Shopee菲律宾:在线购买和出售
2019/11/25 全球购物
静态变量和实例变量的区别
2015/07/07 面试题
激情洋溢的毕业生就业求职信
2014/03/15 职场文书
家长寄语大全
2014/04/02 职场文书
2015年简历自我评价范文
2015/03/11 职场文书
分享15个Webpack实用的插件!!!
2021/03/31 Javascript
python解决12306登录验证码的实现
2021/04/18 Python
python中subplot大小的设置步骤
2021/06/28 Python