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实现日历控件(年月日关闭按钮)
Dec 12 Javascript
js 实现菜单左右滚动显示示例介绍
Nov 21 Javascript
jquery实现拖动效果(代码分享)
Jan 25 Javascript
vue 粒子特效的示例代码
Sep 19 Javascript
angular4自定义组件详解
Sep 28 Javascript
vue 过滤器filter实例详解
Mar 14 Javascript
解决vue+element 键盘回车事件导致页面刷新的问题
Aug 25 Javascript
解决angular2在双向数据绑定时[(ngModel)]无法使用的问题
Sep 13 Javascript
Vue设置长时间未操作登录自动到期返回登录页
Jan 22 Javascript
vuejs element table 表格添加行,修改,单独删除行,批量删除行操作
Jul 18 Javascript
vue实现用户长时间不操作自动退出登录功能的实现代码
Jul 23 Javascript
使用js和canvas实现时钟效果
Sep 08 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+SQL 注入攻击的技术实现以及预防办法
2011/01/27 PHP
解析PHP汉字转换拼音的类
2013/06/18 PHP
PHP过滤★等特殊符号的正则
2014/01/27 PHP
用正则xmlHttp实现的偷(转)
2007/01/22 Javascript
extjs4 treepanel动态改变行高度示例
2013/12/17 Javascript
php,js,css字符串截取的办法集锦
2014/09/26 Javascript
实例讲解JQuery中this和$(this)区别
2014/12/08 Javascript
jQuery使用empty()方法删除元素及其所有子元素的方法
2015/03/26 Javascript
JavaScript中iframe实现局部刷新的几种方法汇总
2016/01/06 Javascript
详解Node.js包的工程目录与NPM包管理器的使用
2016/02/16 Javascript
如何使用jquery修改css中带有!important的样式属性
2016/04/28 Javascript
Jquery Easyui搜索框组件SearchBox使用详解(19)
2016/12/17 Javascript
Angular2 组件间通过@Input @Output通讯示例
2017/08/24 Javascript
详解vue-cli之webpack3构建全面提速优化
2017/12/25 Javascript
详解vue 数组和对象渲染问题
2018/09/21 Javascript
arcgis.js控制地图地体的显示范围超出区域自动弹回(实现思路)
2021/01/28 Javascript
[02:41]DOTA2亚洲邀请赛小组赛第三日 赛事回顾
2015/02/01 DOTA
python 示例分享---逻辑推理编程解决八皇后
2014/07/20 Python
python logging日志模块的详解
2017/10/29 Python
selenium+python实现自动化登录的方法
2018/09/04 Python
Python Pywavelet 小波阈值实例
2019/01/09 Python
Python实战之制作天气查询软件
2019/05/14 Python
使用python脚本自动创建pip.ini配置文件代码实例
2019/09/20 Python
如何在sublime编辑器中安装python
2020/05/20 Python
应用电子技术专业个人求职信
2013/09/21 职场文书
留学生如何写好自荐信
2013/12/27 职场文书
汽车维修专业个人求职信范文
2014/01/01 职场文书
长安大学毕业生自我鉴定
2014/01/17 职场文书
酒店保安员岗位职责
2014/01/31 职场文书
《雷鸣电闪波尔卡》教学反思
2014/02/23 职场文书
大学生怎样写好自荐信
2014/02/25 职场文书
幼儿园优秀班主任事迹材料
2014/05/14 职场文书
以幸福为主题的活动方案
2014/08/22 职场文书
先进个人事迹材料范文
2014/12/30 职场文书
启动Tomcat时出现大量乱码的解决方法
2021/06/21 Java/Android
CSS实现背景图片全屏铺满自适应的3种方式
2022/07/07 HTML / CSS