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 相关文章推荐
删除重复数据的算法
Nov 23 Javascript
Jquery如何实现点击时高亮显示代码
Jan 22 Javascript
基于JQuery实现仿网易邮箱全屏动感滚动插件fullPage
Sep 20 Javascript
JavaScript中的闭包
Feb 24 Javascript
详解angularjs结合pagination插件实现分页功能
Feb 10 Javascript
正则表达式基本语法及表单验证操作详解【基于JS】
Apr 07 Javascript
jQuery图片加载失败替换默认图片方法汇总
Nov 29 jQuery
11行JS代码制作二维码生成功能
Mar 09 Javascript
vue-cli 组件的导入与使用教程详解
Apr 11 Javascript
Angular2中监听数据更新的方法
Aug 31 Javascript
JS常见面试试题总结【去重、遍历、闭包、继承等】
Aug 27 Javascript
基于vuex实现购物车功能
Jan 10 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
PHP新手上路(十)
2006/10/09 PHP
PHP--用万网的接口实现域名查询功能
2012/12/13 PHP
php获取指定日期之间的各个周和月的起止时间
2014/11/24 PHP
PHP中SERIALIZE和JSON的序列化与反序列化操作区别分析
2016/10/11 PHP
自动更新作用
2006/10/08 Javascript
在UpdatePanel内jquery easyui效果失效的解决方法
2010/04/11 Javascript
js继承call()和apply()方法总结
2014/12/08 Javascript
浅谈Javascript中Object与Function对象
2015/09/26 Javascript
JavaScript学习小结(7)之JS RegExp
2015/11/29 Javascript
js基于setTimeout与setInterval实现多线程
2016/06/17 Javascript
jQuery视差滚动效果网页实现方法经验总结
2016/09/29 Javascript
jquery 正整数数字校验正则表达式
2017/01/10 Javascript
原生js实现旋转木马轮播图效果
2017/02/27 Javascript
vue-loader教程介绍
2017/06/14 Javascript
angular学习之从零搭建一个angular4.0项目
2017/07/10 Javascript
AngularJS日期格式化常见操作实例分析
2018/05/17 Javascript
vue移动端微信授权登录插件封装的实例
2018/08/28 Javascript
vue实现移动端轻量日期组件不依赖第三方库的方法
2019/04/28 Javascript
.netcore+vue 实现压缩文件下载功能
2020/09/24 Javascript
[05:04]完美世界携手游戏风云打造 卡尔工作室地图界面篇
2013/04/23 DOTA
Python做文本按行去重的实现方法
2016/10/19 Python
基于Django静态资源部署404的解决方法
2019/07/28 Python
Django学习之文件上传与下载
2019/10/06 Python
pycharm双击无响应(打不开问题解决办法)
2020/01/10 Python
Django在Model保存前记录日志实例
2020/05/14 Python
opencv-python的RGB与BGR互转方式
2020/06/02 Python
鞋子女王塔玛拉·梅隆同名奢侈品牌:Tamara Mellon
2017/11/22 全球购物
幼儿运动会邀请函
2014/01/17 职场文书
创建精神文明单位实施方案
2014/03/08 职场文书
个人授权委托书范文
2014/09/21 职场文书
早读课迟到检讨书
2014/09/25 职场文书
中学生旷课检讨书模板
2014/10/08 职场文书
民事起诉状范文
2015/05/19 职场文书
Python实现byte转integer
2021/06/03 Python
浅析Python中的套接字编程
2021/06/22 Python
解决mysql的int型主键自增问题
2021/07/15 MySQL