vue 数据埋点

news2024/11/19 15:30:43

最近菜鸟做项目,需要做简单的数据埋点,不是企业级的,反正看渡一的视频,企业级特别复杂,包括但不限于:错误收集、点击地方、用户行为……

菜鸟的需求就是简单收集一下用户的ip、地址、每个界面的访问时间,而且面向的是全球用户,所以自己简单写了。

文章目录

  • 一、获取IP、地址
  • 二、数据埋点
    • 解决传入的是跳转后的界面
    • 解决监听不到关闭网页的问题
  • 三、按钮埋点

一、获取IP、地址

这里菜鸟最开始想到的就是高德、腾讯地图这样的平台,里面都是有ip逆向解析的,但是菜鸟一看高德的api,发现不支持国外!!!
在这里插入图片描述
然后百度虽然支持,但是也不是很准确,最重要的一点是总是提示我跨域了,不知道咋解决!!!
在这里插入图片描述
所以菜鸟就在网上找到一个免费且比较准确的

https://ipinfo.io/account/profile

反正电脑不是手机,定位确实不好搞,反正菜鸟感觉定位的地方就是离你最近的转发基站的位置,而不是你本来的位置!

希望有知道可以精确定位的读者可以 指点江山,激扬文字

二、数据埋点

这里菜鸟最开始想的是 vue3 的 mixins,发现 vue3 不推荐 mixins,但是可以直接使用组合式 API 的组合式函数,就相当于把mixins当函数提出去,然后需要用到的时候直接引入就行!

然后菜鸟写的代码就是这样的了:
src/mixins/pagetime.js

/**
 * 书写界面停留时间函数
 */
import { onBeforeUnmount } from "vue";
import { DataburialpointApi } from "@/network/api";
import { useRoute } from "vue-router";

// 按照惯例,组合式函数名以“use”开头
export function usePageTime() {
  const _routeObj = {
    "/content": "首页",
    "/services/0": "NGS- Whole Genome Sequencing",
    "/services/1": "NGS- mRNA Sequencing",
    "/services/2": "NGS- Small RNA Sequencing",
    "/services/3": "NGS-Lnc RNA Sequencing",
    "/services/4": "NGS- Metagenome Sequencing",
    "/services/5": "NGS- Microbial diversity Sequencing",
    "/services/6": "NGS- Hi-C Sequencing",
    "/services/7": "Nanopore- Nanopore Ultra-long Sequencing",
    "/services/8": "Nanopore- Nanopore Sequencing",
    "/services/9": "Nanopore- Direct RNA Sequencing",
    "/services/10": "Nanopore- Lnc RNA Sequencing",
    "/services/11": "Nanopore- CircRNA Sequencing",
    "/services/12": "Nanopore- TAIL Iso Sequencing",
    "/services/13": "Nanopore- Isoform Sequencing",
    "/services/14": "Nanopore- Direct-CDNA Sequencing",
    "/services/15": "Nanopore- Single-cell full-length transcriptome Sequencing",
    "/services/16": "Nanopore- Full-length 16S/18S/ITS Amplicon Sequencing",
    "/services/17": "Nanopore- 16S-23S Amplicon Metagenomic Sequencing",
    "/services/18": "Nanopore- Metagenome Sequencing",
    "/services/19": "Nanopore- PORE-C Sequencing",
    "/services/20": "Pacbio Revio- Revio Sequencing",
    "/resources/sample": "资源-样本要求",
    "/about": "关于我们",
    "/contactus": "联系我们",
  };
  let _startTime = new Date();
  let _useTime = 0;
  // 路由菜单相关
  let route = useRoute();
  onBeforeUnmount(() => {
    _useTime = new Date() - _startTime;
    console.log(_routeObj[route.path]);
    console.log(_useTime);
    let _formdata = {};
    _formdata.visitorId = localStorage.getItem("userId");
    _formdata.url = route.path;
    _formdata.classify = _routeObj[route.path];
    _formdata.time = _useTime;
    DataburialpointApi(_formdata)
      .then((res) => {
        console.log(res);
      })
      .catch((err) => {
        console.log(err);
      });
  });
}

结果压根不靠谱,这样发送给后端的是跳转后的界面,而不是跳转前的,所以每次都是把上一个界面的访问时间和新跳转的界面发送过去了!!!而且还有一个bug 就是别人不切换界面,那我就不知道别人上一个界面访问了多久,且当别人访问一个界面后,直接点击关闭标签,也无法知道这个界面访问了多久

接下来一个一个解决!

解决传入的是跳转后的界面

菜鸟发现app.vue里有监听路由,那岂不是可以监听路由改变的时候发一个emitter,然后这里监听到了,取旧的值不就行了?于是代码变成了这样:
src/mixins/pagetime.js

/**
 * 书写界面停留时间函数
 */
import { ref, onBeforeUnmount } from "vue";
import { DataburialpointApi } from "@/network/api";
import emitter from "@/tools/eventBus";

// 按照惯例,组合式函数名以“use”开头
export function usePageTime() {
  const _routeObj = {
    "/content": "首页",
    "/services/0": "NGS- Whole Genome Sequencing",
    "/services/1": "NGS- mRNA Sequencing",
    "/services/2": "NGS- Small RNA Sequencing",
    "/services/3": "NGS-Lnc RNA Sequencing",
    "/services/4": "NGS- Metagenome Sequencing",
    "/services/5": "NGS- Microbial diversity Sequencing",
    "/services/6": "NGS- Hi-C Sequencing",
    "/services/7": "Nanopore- Nanopore Ultra-long Sequencing",
    "/services/8": "Nanopore- Nanopore Sequencing",
    "/services/9": "Nanopore- Direct RNA Sequencing",
    "/services/10": "Nanopore- Lnc RNA Sequencing",
    "/services/11": "Nanopore- CircRNA Sequencing",
    "/services/12": "Nanopore- TAIL Iso Sequencing",
    "/services/13": "Nanopore- Isoform Sequencing",
    "/services/14": "Nanopore- Direct-CDNA Sequencing",
    "/services/15": "Nanopore- Single-cell full-length transcriptome Sequencing",
    "/services/16": "Nanopore- Full-length 16S/18S/ITS Amplicon Sequencing",
    "/services/17": "Nanopore- 16S-23S Amplicon Metagenomic Sequencing",
    "/services/18": "Nanopore- Metagenome Sequencing",
    "/services/19": "Nanopore- PORE-C Sequencing",
    "/services/20": "Pacbio Revio- Revio Sequencing",
    "/resources/sample": "资源-样本要求",
    "/about": "关于我们",
    "/contactus": "联系我们",
  };
  let _startTime = new Date();
  let _useTime = ref(0);

  emitter.on("pageTime", (oldValue) => {
    _useTime.value = new Date() - _startTime;
    console.log(_routeObj[oldValue]);
    console.log(_useTime.value);
    let _formdata = {};
    _formdata.visitorId = localStorage.getItem("userId");
    _formdata.url = oldValue;
    _formdata.classify = _routeObj[oldValue];
    _formdata.time = _useTime.value;
    DataburialpointApi(_formdata)
      .then((res) => {
        console.log(res);
      })
      .catch((err) => {
        console.log(err);
      });
  });

  onBeforeUnmount(() => {
    emitter.off("pageTime");
  });
}

但是菜鸟一想,不对呀,全部和路由相关,直接写路由里面不好吗?这样写成mixins还要每个界面都这这样引入!

// mixin
import { usePageTime } from "@/mixin/pagetime";
usePageTime();

所以直接用路由守卫了,代码如下:
src/mixins/pagetime.js

import { createRouter, createWebHashHistory } from "vue-router";
import Home from "@/views/home/home.vue";
import { DataburialpointApi } from "@/network/api";

const routes = [
  {
    path: "/",
    name: "home",
    redirect: "/content",
    component: Home,
    children: [
      {
        path: "/content",
        name: "content",
        component: () => import("../views/content/content.vue"),
      },
      {
        path: "/services/:type",
        name: "services",
        component: () => import("../views/services/services.vue"),
      },
      {
        path: "/resources",
        name: "resources",
        redirect: "/resources/sample",
        component: () => import("../views/resources/resources.vue"),
        children: [
          {
            path: "/resources/sample",
            name: "sample",
            component: () => import("../views/resources/components/sample.vue"),
          },
        ],
      },
      {
        path: "/news",
        name: "news",
        component: () => import("../views/news/news.vue"),
      },
      {
        path: "/about",
        name: "about",
        component: () => import("../views/about/aboutus.vue"),
      },
      {
        path: "/contactus",
        name: "contactus",
        component: () => import("../views/contactus/contactus.vue"),
      },
    ],
  },
];

const router = createRouter({
  history: createWebHashHistory(),
  routes,
});

let startTime = Date.now();
localStorage.setItem("lastPageTime", startTime);
let currentTime;
const _routeObj = {
  "/content": "首页",
  "/services/0": "NGS- Whole Genome Sequencing",
  "/services/1": "NGS- mRNA Sequencing",
  "/services/2": "NGS- Small RNA Sequencing",
  "/services/3": "NGS-Lnc RNA Sequencing",
  "/services/4": "NGS- Metagenome Sequencing",
  "/services/5": "NGS- Microbial diversity Sequencing",
  "/services/6": "NGS- Hi-C Sequencing",
  "/services/7": "Nanopore- Nanopore Ultra-long Sequencing",
  "/services/8": "Nanopore- Nanopore Sequencing",
  "/services/9": "Nanopore- Direct RNA Sequencing",
  "/services/10": "Nanopore- Lnc RNA Sequencing",
  "/services/11": "Nanopore- CircRNA Sequencing",
  "/services/12": "Nanopore- TAIL Iso Sequencing",
  "/services/13": "Nanopore- Isoform Sequencing",
  "/services/14": "Nanopore- Direct-CDNA Sequencing",
  "/services/15": "Nanopore- Single-cell full-length transcriptome Sequencing",
  "/services/16": "Nanopore- Full-length 16S/18S/ITS Amplicon Sequencing",
  "/services/17": "Nanopore- 16S-23S Amplicon Metagenomic Sequencing",
  "/services/18": "Nanopore- Metagenome Sequencing",
  "/services/19": "Nanopore- PORE-C Sequencing",
  "/services/20": "Pacbio Revio- Revio Sequencing",
  "/resources/sample": "资源-样本要求",
  "/about": "关于我们",
  "/contactus": "联系我们",
};

router.beforeEach((to, from) => {
  // console.log(to, from);
  if (to && _routeObj[from.path]) {
    // 第一步:页面跳转后记录一下当前的时间 currentTime
    currentTime = Date.now();
    // 第二步:通过计算currentTime - startTime 的 差值 之后,再上报数据
    let _formdata = {};
    _formdata.visitorId = localStorage.getItem("userId");
    _formdata.url = from.path;
    _formdata.classify = _routeObj[from.path];
    _formdata.time = currentTime - startTime;
    // console.log(_formdata);
    // debugger;
    DataburialpointApi(_formdata)
      .then((res) => {
        console.log(res);
      })
      .catch((err) => {
        console.log(err);
      });
    // 第三步:每次都要初始化一下 startTime
    startTime = Date.now();
    localStorage.setItem("lastPageTime", startTime);
  }
});
export default router;

注意:
上面的 localStorage.setItem(“lastPageTime”, startTime); 是后续做 解决监听不到关闭网页的问题 的时候加上的!

解决监听不到关闭网页的问题

在app.vue里面加上监听页面关闭事件,这个必须用原生js,vue 的 onBeforeUnmount 根本不能在界面标签关闭时做操作!

import { useMainStore } from "@/store";
import { useRoute } from "vue-router";
// 路由菜单相关
let route = useRoute();
const mainStore = useMainStore();
onMounted(() => {
  // 监听页面关闭事件
  window.addEventListener("beforeunload", function (event) {
    // 计算页面停留时间(以毫秒为单位)
    const stayTime = new Date() - localStorage.getItem("lastPageTime");

    let _formdata = {};
    _formdata.visitorId = localStorage.getItem("userId");
    _formdata.url = route.path;
    _formdata.classify = mainStore.routeObj[route.path];
    _formdata.time = stayTime;

    // console.log(_formdata);
    // debugger;

    DataburialpointApi(_formdata)
      .then((res) => {
        console.log(res);
      })
      .catch((err) => {
        console.log(err);
      });

    // 确保关闭页面时不会阻止默认行为
    delete event["returnValue"];
  });
});

注意:
这里 mainStore.routeObj 和上面的 _routeObj 是同一个东西,但是不能直接在 route/index.js 中使用 pinia,会报错,搜索是因为在 pinia 挂载之前使用了,具体怎么解决不知道!!!望读者 指点江山,激扬文字!!!

三、按钮埋点

到这里,菜鸟的需求就结束了,但是菜鸟拓展了一下,其实这个也很简单,就是每个按钮点击请求的时候,让后端统计一下,或者前端请求一下后端的某个接口就行!当然如果能直接封装成 自定义指令 就最好了!!!

参考文章:
vue项目进行前端埋点,记录页面停留时间

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1567109.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ubuntu20.04使用Neo4j导入CSV数据可视化知识图谱

1.安装JDK( Ubuntu20.04 JDK11) sudo apt-get install openjdk-11-jdk -y java -version which java ls -l /usr/bin/java ls -l /etc/alternatives/java ls -l /usr/lib/jvm/java-11-openjdk-amd64/bin/java确认安装路径为/usr/lib/jvm/java-11-openjd…

【VUE+ElementUI】el-table表格固定列el-table__fixed导致滚动条无法拖动

【VUEElementUI】el-table表格固定列el-table__fixed导致滚动条无法拖动 背景 当设置了几个固定列之后,表格无数据时,点击左侧滚动条却被遮挡,原因是el-table__fixed过高导致的 解决 在index.scss中直接加入以下代码即可 /* 设置默认高…

最优算法100例之26-翻转单词顺序

专栏主页:计算机专业基础知识总结(适用于期末复习考研刷题求职面试)系列文章https://blog.csdn.net/seeker1994/category_12585732.html 题目描述 牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句…

【北京迅为】《iTOP-3588开发板系统编程手册》第1章 系统编程初探

RK3588是一款低功耗、高性能的处理器,适用于基于arm的PC和Edge计算设备、个人移动互联网设备等数字多媒体应用,RK3588支持8K视频编解码,内置GPU可以完全兼容OpenGLES 1.1、2.0和3.2。RK3588引入了新一代完全基于硬件的最大4800万像素ISP&…

基于单片机的超声波测距仪设计_kaic

摘 要 如今社会持续深化转型,在人工智能领域,传感器采集外部数据,经过处理器对数 据运算和处理,从而实现相应的功能。比如自动驾驶技术中,超声波传感器应用广泛, 超声波是一种频率在 20khz 以上的声波&…

STM32-04基于HAL库(CubeMX+MDK+Proteus)中断案例(按键中断扫描)

文章目录 一、功能需求分析二、Proteus绘制电路原理图三、STMCubeMX 配置引脚及模式,生成代码四、MDK打开生成项目,编写HAL库的按键检测代码五、运行仿真程序,调试代码 一、功能需求分析 在完成GPIO输入输出案例之后,开始新的功能…

如何防止IP泄露,安全匿名上网?

当互联网成为每个家庭的重要组成部分后,IP地址就成了你的虚拟地址。您的请求从该地址开始,然后 Internet 将消息发送回该地址。那么,您担心您的地址被泄露吗? 对于安全意识高或者某些业务需求的用户,如果您正在寻找保护…

用户认证安全性测试

用户认证安全性测试 认证与会话管理认证--Authentication01 常见认证方式02 session认证Session Fixation攻击Session保持攻击 03 Token认证多因素认证session和token区别 04 暴力破解密码的那些事密码设置推荐策略 会话--Authorization 权限控制权限管理方式垂直权限管理水平权…

redis 集群 (主从复制 哨兵模式 cluster)

目录 一 主从复制 (一)相关理论 1,主从复制定义 2,主从复制的作用 3,主从复制架构图 4 sync 同步过程 5,主从复制流程 (二) 实验模拟 1, 实验环境 2, 修…

【ArduinoQuartus】在小脚丫STEP CYC10上安装PulseRain Reindeer并在软核上运行基础功能

【Arduino&Quartus】在小脚丫STEP CYC10上安装PulseRain Reindeer并在软核上运行基础功能 一、将Reindeer软核下载到STEP CYC10(一)下载PulseRain Reindeer软核(二)配置Reindeer软核到开发板1.将sof文件转换为jic文件2.将jic文…

【动态】江西省小型水库安全监测能力提升试点项目通过验收

近日,由北京国信华源科技有限公司和长江勘测规划设计研究有限责任公司联合承建的江西省小型水库安全监测能力提升试点项目圆满通过验收。 在项目业主单位的组织下,省项目部、特邀专家、县水利局二级项目部以及项目设计、监理、承建等单位的代表组成验收工…

OpenHarmony实战:小型系统器件驱动移植

本章节讲解如何移植各类器件驱动。 LCD驱动移植 移植LCD驱动的主要工作是编写一个驱动,在驱动中生成模型的实例,并完成注册。 这些LCD的驱动被放置在源码目录//drivers/hdf_core/framework/model/display/driver/panel中。 创建Panel驱动 创建HDF驱动…

Nginx从安装到高可用实用教程!

一、Nginx安装 1、去官网http://nginx.org/下载对应的nginx包,推荐使用稳定版本 2、上传nginx到linux系统 3、安装依赖环境 (1)安装gcc环境 yum install gcc-c(2)安装PCRE库,用于解析正则表达式 yum install -y pcre pcre-devel(3)zlib压缩和解压缩…

C++输出格式控制

setprecision(n)可控制输出流显示浮点数的数字个数。C默认的流输出数值有效位是6,所以不管数据是多少,都只输出六位。如果setprecision(n)与setiosflags(ios::fixed)或者setiosflags(ios_base::fixed)合用,可以控制小数点右边的数字个数。set…

中间件复习之-RPC框架

什么是RPC框架? RPC(Remote Procedure Call):远程过程调用。当多个应用部署在多个服务器上时,由于他们不在一个内存空间上,因此需要网络来进行通信,而RPC允许它像调用本地方法一样调用远程服务。 RPC原理 服务消费方通过RPC客户…

UE5 C++ LevelSequence

前言 最近在用UE C做一些功能,用到了Level Sequence功能,但是看了下UE官方论坛包括一些文章基本没有关于C 处理Level Sequence 这块内容,有的也是一些修改或者源码原理的一些内容分析,接下来我就把我新建Sequence包括一些库的调用…

CleanMyMac X中文---一键优化Mac,释放存储空间新利器

CleanMyMac X是一款专业的苹果笔记本系统管理工具,旨在全面优化和清理Mac内存,释放更多有效空间,使Mac始终保持最佳状态。它具备智能扫描功能,能够准确识别并清理系统垃圾、冗余文件以及大型和废旧文件,有效释放磁盘空…

深入了解美颜技术开发:利用深度学习打造直播美颜SDK

直播美颜不仅让主播在镜头前更加自信,也让观众享受到更美好的视觉体验。而在美颜技术的背后,深度学习技术正扮演着至关重要的角色。 一、美颜技术的发展历程 这些算法往往无法达到自然的效果,容易出现过度处理或者失真的情况。随着深度学习…

CSS3新增的语法(四)

CSS3新增的语法(四)【布局】 14. 多列布局15.伸缩盒模型1. 伸缩盒模型简介2. 伸缩容器、伸缩项目3. 主轴与侧轴4. 主轴方向5. 主轴换行方式6. flex-flow7. 主轴对齐方式8. 侧轴对齐方式8.1 一行的情况8.2 多行的情况 9.flex 实现水平垂直居中10. 伸缩性1…

【opencv】教程代码 —Histograms_Matching(1)反向投影:在给定图像中寻找特定的颜色或颜色分布...

1. calcBackProject_Demo1.cpp 反向投影函数的使用 /*** file BackProject_Demo1.cpp* brief 示例代码,演示反向投影函数的使用* author OpenCV团队*/#include "opencv2/imgproc.hpp" // 包括图像处理相关功能的头文件 #include "opencv2/imgcodecs…