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 相关文章推荐
JavaScript高级程序设计 XML、Ajax 学习笔记
Sep 10 Javascript
js循环改变div颜色具体方法
Jun 25 Javascript
JS定时刷新页面及跳转页面的方法
Jul 04 Javascript
Bootstrap每天必学之js插件
Nov 30 Javascript
JS生成和下载二维码的代码
Dec 07 Javascript
详解使用fetch发送post请求时的参数处理
Apr 05 Javascript
js 监控iframe URL的变化实例代码
Jul 12 Javascript
基于vue开发的在线付费课程应用过程
Jan 25 Javascript
vue强制刷新组件的方法示例
Feb 28 Javascript
mpvue全局引入sass文件的方法步骤
Mar 06 Javascript
详解基于Wepy开发小程序插件(推荐)
Aug 01 Javascript
jQuery 选择器用法实例分析【prev + next】
May 22 jQuery
详解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 strtotime函数用法、实现原理和源码分析
2015/02/04 PHP
phpstudy的php版本自由修改的方法
2017/10/18 PHP
Laravel框架Eloquent ORM简介、模型建立及查询数据操作详解
2019/12/04 PHP
js+FSO遍历文件夹下文件并显示
2007/03/07 Javascript
JavaScript对象模型-执行模型
2008/04/28 Javascript
JQuery实现简单时尚快捷的气泡提示插件
2012/12/20 Javascript
javascript制作网页图片上实现下雨效果
2015/02/26 Javascript
Vue+axios 实现http拦截及路由拦截实例
2017/04/25 Javascript
Bootstrap 表单验证formValidation 实现远程验证功能
2017/05/17 Javascript
使用Require.js封装原生js轮播图的实现代码
2017/06/15 Javascript
js对象实例详解(JavaScript对象深度剖析,深度理解js对象)
2017/09/21 Javascript
vue购物车插件编写代码
2017/11/27 Javascript
微信小程序progress组件使用详解
2018/01/31 Javascript
vue获取时间戳转换为日期格式代码实例
2019/04/17 Javascript
vue组件是如何解析及渲染的?
2021/01/13 Vue.js
[01:02:10]DOTA2上海特级锦标赛B组小组赛#2 VG VS Fnatic第一局
2016/02/26 DOTA
[01:33:30]DOTA2-DPC中国联赛 正赛 RNG vs Phoenix BO3 第二场 2月5日
2021/03/11 DOTA
详解Python中的文件操作
2016/08/28 Python
Python 异常处理的实例详解
2017/09/11 Python
解决Pandas的DataFrame输出截断和省略的问题
2019/02/08 Python
详解Python 定时框架 Apscheduler原理及安装过程
2019/06/14 Python
Python获取命令实时输出-原样彩色输出并返回输出结果的示例
2019/07/11 Python
python plt可视化——打印特殊符号和制作图例代码
2020/04/17 Python
LN-CC美国:伦敦时尚生活的缩影
2019/02/19 全球购物
园长自我鉴定
2013/10/06 职场文书
风险评估实施方案
2014/03/09 职场文书
小学生手册家长评语
2014/04/16 职场文书
学校对教师的评语
2014/04/28 职场文书
拒绝黄毒毒宣传标语
2014/06/26 职场文书
群众路线自我剖析范文
2014/11/04 职场文书
党的群众路线教育实践活动个人对照检查材料(四风)
2014/11/05 职场文书
晚会闭幕词
2015/01/28 职场文书
幼儿园新生开学寄语
2015/05/27 职场文书
python字符串常规操作大全
2021/05/02 Python
pytorch--之halfTensor的使用详解
2021/05/24 Python
Win11怎么修改电源模式?Win11修改电源模式的方法
2022/04/05 数码科技