阅读 242

Intersection Observer API 实现数据埋点 批量曝光

基于NuxtJS 2.x构建的项目实现

官网介绍:MDN Web Docs 之 Intersection Observer API

  • 1、new IntersectionObserver() 实例化一个全局_observer,每个 DOM 节点自行把自己加入_observer 的观察列表 (此处会用 Vue 的指令来实现)

  • 2、当某个 DOM 节点进入视窗,收集该 DOM 的信息,存进一个全局数组 dotArr 中,然后取消对该 DOM 的观察

  • 3、从 dotArr 中取数据上传

    • 跑定时器,每隔 N 秒检查一次,如果 dotArr 有数据,就直接上报;

    • 如果 N 秒内,dotArr 的数据量大于某个量 maxNum,不等定时器,直接全部上报

  • 4、不漏以及不重复上报数据,用户离开页面前的边界数据处理

    • 浏览器环境:dotArr 同时存一份在 localStorage 中,同步更新数据(增加或者上报完后清空),如果用户真的在 N 秒的间隔内,而数据又不够最大上报量 maxNum 就离开了页面,那么这批数据就等用户下次再进页面时,直接从 localStorage 中取出来上传。当然如果这个用户再也不进页面或者清空了浏览器缓存,这一点点数据丢失是可以接受。

曝光监听

  1. 创建 intersection-observer.js 文件

// 安装 intersection-observer 插件 npm install intersection-observer --save-dev // 创建观察文件 intersection-observer.js import "intersection-observer"; import axios from "axios"; // 数据上报方法,即网络请求 const platformExposure = (dotDataArr) => {   axios     .post("/api/xxx/exposure", { para: { list: dotDataArr } }) }; // 节流的时间,默认是100ms IntersectionObserver.prototype.THROTTLE_TIMEOUT = 300; const localStorage = window.localStorage; export default class Exposure {   constructor(maxNum = 200) {     this.dotDataArr = []; // 进入视窗的DOM节点的数据     this.maxNum = maxNum;     this.timeout = 1 * 1000 * 60; // 间隔时间上传一次     this._timer = 0;     this._observer = null; // 观察者的集合     this.init(); // 全局只会实例化一次Exposure类   }   init() {     const self = this;     // init只会执行一次,边界处理方法,把浏览器localStorage里面的剩余数据上传     this.dotFromLocalStorage();     this._observer = new IntersectionObserver(       (entries, observer) => {         // 每一个产品进入视窗时都会触发         entries.forEach((entry) => {           if (entry.isIntersecting) {             // 清除当前定时器             clearTimeout(self._timer);             // 把相关的数据直接放DOM上面了,比如 <div :data-dot="哈哈" ></div>             // const ctm = entry.target.attributes['data-dot'].value             const dataset = entry.target.dataset;             const ctm = {               platform_id: dataset.id, // 产品id 必填             };             // 收集数据,进待上报的数据数组             self.dotDataArr.push(ctm);             // 收集到数据后,取消对该DOM节点的观察             self._observer.unobserve(entry.target);             // 超过一定数量直接上传             if (self.dotDataArr.length >= self.maxNum) {               self.dot();             } else {               // 否则,直接缓存               self.storeIntoLocalstorage(self.dotDataArr);               if (self.dotDataArr.length > 0) {                 // 不断有新的ctm进来,接下来如果没增加,自动n秒后打点                 self._timer = window.setTimeout(() => {                   self.dot();                 }, self.timeout);               }             }           }         });       },       {         root: null, // 指定根目录,也就是当目标元素显示在这个元素中时会触发监控回调。 默认值为null,即浏览器窗口         rootMargin: "0px", // 设定root元素的边框区域         threshold: 0.5, // number或number数组,控制target元素进入root元素中可见性超过的阙值,达到阈值会触发函数,也可以使用数据来让元素在进入时在不同的可见度返回多次值       }     );   }   // 每个DOM元素通过全局唯一的Exposure的实例来执行该add方法,将自己添加进观察者中   add(entry) {     this._observer && this._observer.observe(entry.el);   }   // 上传并更新缓存   dot() {     const dotDataArr = this.dotDataArr.splice(0, this.maxNum);     platformExposure(dotDataArr);     this.storeIntoLocalstorage(this.dotDataArr);   }   // 缓存数据   storeIntoLocalstorage(dotDataArr) {     localStorage.setItem("dotDataArr", JSON.stringify(dotDataArr));   }   // 上传数据   dotFromLocalStorage() {     const ctmsStr = JSON.parse(localStorage.getItem("dotDataArr"));     if (ctmsStr && ctmsStr.length > 0) {       platformExposure(ctmsStr);     }   } } 复制代码

曝光指令

  1. 完成曝光指令文件 directives.client.js

import Vue from "vue"; import Exposure from "./intersection-observer"; // exp 全局唯一的实例 const exp = new Exposure(); Vue.directive("exp-dot", {   bind(el, binding, vnode) {     // 每个使用了该指令的商品都会自动add自身进观察者中     exp.add({ el, val: binding.value });   },   update(newValue, oldValue) {     // 值更新时的工作     // 也会以初始值为参数调用一次, 此时可以根据传值类型来进行相应埋点行为的请求处理   },   unbind() {     // 清理工作   }, }); 复制代码

  1. 在配置文件nuxt.config.js中引入指令文件directives.client.js,其中client代表只在客户端生效

// nuxt.config.js module.exports = {   mode: "universal",   plugins: [{ src: "~plugins/directives.client.js" }], }; 复制代码

实战使用

核心使用就是v-exp-dot

<template>   <div class="mescroll">     <div class="list-product">       <div         class="list-item"         v-for="(item, index) in listData"         :key="item.id"         :item="item"         :data-id="item.id"         :data-url="item.url"         v-exp-dot       />     </div>   </div> </template>


作者:时光足迹
链接:https://juejin.cn/post/7018430369321975822

文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐