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 相关文章推荐
How to Auto Include a Javascript File
Feb 02 Javascript
javascript 写类方式之三
Jul 05 Javascript
JQuery对checkbox操作 (循环获取)
May 20 Javascript
Javascript代码在页面加载时的执行顺序介绍
May 03 Javascript
使用OpenLayers3 添加地图鼠标右键菜单
Dec 29 Javascript
Angularjs使用directive自定义指令实现attribute继承的方法详解
Aug 05 Javascript
Node.js制作简单聊天室
Jan 12 Javascript
react中的ajax封装实例详解
Oct 17 Javascript
C#实现将一个字符转换为整数
Dec 12 Javascript
jQuery替换节点元素的操作方法
Mar 18 jQuery
基于Element封装一个表格组件tableList的使用方法
Jun 29 Javascript
JS数据类型分类及常用判断方法
Nov 19 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 加密/解密函数 dencrypt(动态密文,带压缩功能,支持中文)
2009/01/30 PHP
PHP.vs.JAVA
2016/04/29 PHP
php支付宝系列之电脑网站支付
2018/05/30 PHP
离开页面时检测表单元素是否被修改,提示保存的js代码
2010/08/25 Javascript
基于jquery的网页SELECT下拉框美化代码
2010/10/28 Javascript
利用JavaScript的AngularJS库制作电子名片的方法
2015/06/18 Javascript
简述Jquery与DOM对象
2015/07/10 Javascript
Node.js巧妙实现Web应用代码热更新
2015/10/22 Javascript
javascript中数组(Array)对象和字符串(String)对象的常用方法总结
2016/12/15 Javascript
微信小程序自定义模态对话框实例详解
2017/08/16 Javascript
微信小程序scroll-view实现字幕滚动
2018/07/14 Javascript
jquery UI实现autocomplete在获取焦点时得到显示列表功能示例
2019/06/04 jQuery
vue实现将数据存入vuex中以及从vuex中取出数据
2019/11/08 Javascript
微信小程序 flexbox layout快速实现基本布局的解决方案
2020/03/24 Javascript
详解详解Python中writelines()方法的使用
2015/05/25 Python
python实现各进制转换的总结大全
2017/06/18 Python
python2.6.6如何升级到python2.7.14
2018/04/08 Python
python使用turtle库绘制树
2018/06/25 Python
python把数组中的数字每行打印3个并保存在文档中的方法
2018/07/17 Python
python实现点对点聊天程序
2018/07/28 Python
解决python线程卡死的问题
2019/02/18 Python
使用Python检测文章抄袭及去重算法原理解析
2019/06/14 Python
python实现对服务器脚本敏感信息的加密解密功能
2019/08/13 Python
各大浏览器 CSS3 和 HTML5 兼容速查表 图文
2010/04/01 HTML / CSS
电大自我鉴定范文
2013/10/01 职场文书
运动会通讯稿150字
2014/02/15 职场文书
房展策划方案
2014/06/07 职场文书
领导班子四风问题个人对照检查材料
2014/10/04 职场文书
临时用工协议书范本
2014/10/29 职场文书
2014年团工作总结
2014/11/27 职场文书
监察建议书
2015/02/04 职场文书
党员转正申请报告
2015/05/15 职场文书
大学生先进个人主要事迹材料
2015/11/04 职场文书
golang slice元素去重操作
2021/04/30 Golang
MySQL常见优化方案汇总
2022/01/18 MySQL
Django数据库(SQlite)基本入门使用教程
2022/07/07 Python