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代码
Mar 07 Javascript
jQuery中children()方法用法实例
Jan 07 Javascript
基于zepto.js简单实现上传图片
Jun 21 Javascript
AngularJS 作用域详解及示例代码
Aug 17 Javascript
使用Bootstrap + Vue.js实现添加删除数据示例
Feb 27 Javascript
vue-router实现webApp切换页面动画效果代码
May 25 Javascript
详解Node.js 命令行程序开发教程
Jun 07 Javascript
jQuery扩展_动力节点Java学院整理
Jul 05 jQuery
Bootstrap图片轮播效果详解
Oct 17 Javascript
js 中rewrap-ajax.js插件实例代码
Oct 20 Javascript
js的函数的按值传递参数(实例讲解)
Nov 16 Javascript
Vue+elementui 实现复杂表头和动态增加列的二维表格功能
Sep 23 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实现根据浏览器跳转不同语言页面代码
2013/08/02 PHP
PHP 自动加载类原理与用法实例分析
2020/04/14 PHP
javascript日期转换 时间戳转日期格式
2011/11/05 Javascript
检测input每次的输入是否合法遇到汉字输入就有问题
2012/05/23 Javascript
gridpanel动态加载数据的实例代码
2013/07/18 Javascript
JSF中confirm弹出框的用法示例介绍
2014/01/07 Javascript
JS实现闪动的title消息提醒效果
2014/06/20 Javascript
判断浏览器的内核及版本号方法汇总
2015/01/05 Javascript
JavaScript面向对象的实现方法小结
2015/04/14 Javascript
javascript实现根据3原色制作颜色选择器的方法
2015/07/17 Javascript
微信小程序 底部导航栏目开发资料
2016/12/05 Javascript
如何提高Dom访问速度
2017/01/05 Javascript
微信小程序 Button 组件详解及简单实例
2017/01/10 Javascript
数组Array的排序sort方法
2017/02/17 Javascript
使用get方式提交表单在地址栏里面不显示提交信息
2017/02/21 Javascript
fullPage.js和CSS3实现全屏滚动效果
2017/05/05 Javascript
Angular中点击li标签实现更改颜色的核心代码
2017/12/08 Javascript
react router4+redux实现路由权限控制的方法
2018/05/03 Javascript
node+koa2+mysql+bootstrap搭建一个前端论坛
2018/05/06 Javascript
vue2路由方式--嵌套路由实现方法分析
2020/03/06 Javascript
JS实现随机点名器
2020/04/12 Javascript
vue通过v-html指令渲染的富文本无法修改样式的解决方案
2020/05/20 Javascript
Python实现快速排序算法及去重的快速排序的简单示例
2016/06/26 Python
python 使用while写猜年龄小游戏过程解析
2019/10/07 Python
python图形开发GUI库wxpython使用方法详解
2020/02/14 Python
python pandas.DataFrame.loc函数使用详解
2020/03/26 Python
Python利用Xpath选择器爬取京东网商品信息
2020/06/01 Python
PyTorch 中的傅里叶卷积实现示例
2020/12/11 Python
css3 边框、背景、文本效果的实现代码
2018/03/21 HTML / CSS
哥伦比亚最大的网上商店:Linio哥伦比亚
2016/09/25 全球购物
Super-Pharm波兰:药房和香水在一个地方
2020/08/18 全球购物
销售工作人员的自我评价分享
2013/11/10 职场文书
护士岗前培训自我评鉴
2014/02/28 职场文书
初中生考试作弊检讨书
2014/12/14 职场文书
超级礼物观后感
2015/06/15 职场文书
工程移交协议书
2016/03/24 职场文书