0

0

前端怎么埋点?浅析vue自定义指令进行前端埋点的方法

青灯夜游

青灯夜游

发布时间:2022-07-14 20:44:02

|

5401人浏览过

|

来源于掘金社区

转载

怎么进行前端埋点?下面本篇文章给大家介绍一下怎么通过vue自定义指令实现前端埋点,希望对大家有所帮助!

前端怎么埋点?浅析vue自定义指令进行前端埋点的方法

(学习视频分享:vue视频教程

在营销活动中,通过埋点可以获取用户的喜好及交互习惯,从而优化流程,进一步提升用户体验,提高转化率。

在之前的埋点方案实现中,都是在具体的按钮或者图片被点击或者被曝光时主动通过事件去上报埋点。这种方法在项目中埋点比较少时还行,一旦项目中需要大量埋点时,不可避免的要添加很多业务代码。也很大程度上造成了埋点逻辑与业务逻辑的高耦合。

立即学习前端免费学习笔记(深入)”;

为了改造这种情况,我们对于原有的埋点方式做了一些小改进,使得埋点效率得到了极大提升。

在阐述我们的埋点改造之前,有必要对埋点的一些常识做下简单的了解。

埋点上报方式都有哪些?

要知道埋点的类型有很多,上报的方式也是五花八门。前端常见的埋点方法有三种:

  • 手动埋点
  • 可视化埋点
  • 无痕埋点

手动埋点,顾名思义就是纯手动写代码,调用埋点 SDK 提供的函数,在需要埋点的业务逻辑中添加对应方法,上报埋点数据。这种也是之前一直在使用的方法。

可视化埋点是指通过可视化系统配置埋点,这种方式接触的不是很多,就不展开说了。

无痕埋点,也叫自动埋点、全埋点。即对全局所有事件和页面加载周期进行拦截埋点。

一般对哪些数据做埋点?

为了达到数据分析,便于后续的运营及产品策略调整的目的,一般需要对以下几点做埋点统计:

  • 页面埋点:统计用户进入或者离开页面的信息,如页面浏览次数(pv)、浏览页面人数(uv)、页面停留时长、设备信息等
  • 点击埋点:统计用户在页面浏览过程中触发的点击事件,如按钮、导航或者图片的点击次数
  • 曝光埋点:统计具体元素是否得到有效曝光

需求分析

本文是基于最近项目中添加埋点的需求,我们需要的一种理想化方案是:

  • 埋点与业务尽量分离,埋点逻辑更应该是独立于业务的
  • 尽量不对业务代码有侵入
  • 约定规范,通过统一收口来处理埋点逻辑

由于项目是Vue开发的,所以考虑使用自定义指令的方式来完成埋点上报。选择自定义指令的原因也是因为他能一定程度上能让业务和埋点解耦。

页面埋点在框架层面已经帮我们做掉了,这里主要关心的是点击埋点和曝光埋点。

实现思路其实也很清晰:在需要埋点的DOM节点挂载特殊属性,通过埋点SDK监听挂载了相应属性对应的事件,在事件触发时进行埋点数据上报。

那么问题来了,怎么监听呢?

对于点击事件,我们可以采用addEventListener来监听click事件。这很简单。

对于元素的曝光就稍微有点麻烦了。

首先我们来看一下为什么需要监测曝光:

Img.Upscaler
Img.Upscaler

免费的AI图片放大工具

下载

1.png

为了衡量用户对产品的兴趣程度,需要计算区域的点击率(点击次数/曝光次数)。为了保证点击率的准确性,我们必须保证用户真正的浏览到了这些产品(就比如上图中最下方的机酒产品区域,由于需要滚动页面,用户才有可能看到这一区域)。

那么怎么判断元素出现在页面的可视区域呢?

按照以往的做法:监听滚动事件,通过getBoundingClientRect()方法计算监测区域与视窗的位置,然后判断元素是否出现在页面的可视区域内。但是由于scroll事件的频繁触发,性能问题很大。

基于此,浏览器特意为我们打造了一个Intersection ObserverAPI,把性能相关的细节都处理掉,让开发者只关心业务逻辑即可:

2.png

由于用户浏览页面的不确定性,还必须要避免重复的曝光行为。这个在曝光之后,移除观察即可。

代码实现

上面的需求分析还是比较抽象,下面让我们结合代码来看一下最终的实现。

Click 类封装

点击事件的处理相对比较简单,每次点击触发数据上报即可:

// src/directives/track/click.js
import { sendUBT } from "../../utils/ctrip"

export default class Click {
  add(entry) {
    // console.log("entry", entry);
    const traceVal = entry.el.attributes["track-params"].value
    const traceKey = entry.el.attributes["trace-key"].value
    const { clickAction, detail } = JSON.parse(traceVal)
    const data = {
      action: clickAction,
      detail,
    }
    entry.el.addEventListener("click", function() {
      console.log("上报点击埋点", JSON.parse(traceVal))
      console.log("埋点key", traceKey)
      sendUBT(traceKey, data)
    })
  }
}

Exposure 类封装

曝光的相对复杂一些。

首先通过new IntersectionObserver() 实例化一个全局_observer,如果得到有效曝光的(这里当元素出现一半以上则进行曝光),就去获取 DOM 节点上的trace-key(埋点 key)和track-params(埋点 value)。

// src/directives/track/exposure.js
import "intersection-observer"
import { sendUBT } from "../../utils/ctrip"

// 节流时间调整,默认100ms
IntersectionObserver.prototype["THROTTLE_TIMEOUT"] = 300

export default class Exposure {
  constructor() {
    this._observer = null
    this.init()
  }

  init() {
    const self = this

    // 实例化监听
    this._observer = new IntersectionObserver(
      function(entries, observer) {
        entries.forEach((entry) => {
          // 出现在视窗内
          if (entry.isIntersecting) {
            // 获取参数
            // console.log("埋点节点", entry.target.attributes);
            const traceKey = entry.target.attributes["trace-key"].value
            const traceVal = entry.target.attributes["track-params"].value
            console.log("traceKey", traceKey)
            console.log("traceVal", traceVal)

            const { exposureAction, detail } = JSON.parse(traceVal)
            const data = {
              action: exposureAction,
              detail,
            }

            // 曝光之后取消观察
            self._observer.unobserve(entry.target)

              self.track(traceKey, data)
          }
        })
      },
      {
        root: null,
        rootMargin: "0px",
        threshold: 0.5, // 元素出现面积,0 - 1,这里当元素出现一半以上则进行曝光
      }
    )
  }

  /**
   * 元素添加监听
   *
   * @param {*} entry
   * @memberof Exposure
   */
  add(entry) {
    this._observer && this._observer.observe(entry.el)
  }

  /**
   * 埋点上报
   *
   * @memberof Exposure
   */
  track(traceKey, traceVal) {
    // console.log("曝光埋点", traceKey, JSON.parse(traceVal));
    sendUBT(traceKey, traceVal)
  }

}

指令封装

有了点击和曝光类,下一步就是 Vue 指令的封装了,也是之所以能实现半自动埋点的核心。

这里存在一个场景就是对于同一个按钮或者图片,同时存在既需要点击埋点又需要曝光埋点的场景。所以在指令的设计时支持了单独传入和同时传入的场景:

  • v-track:click|exposure
  • v-track:exposure
// src/directives/track/index.js
import Vue from "vue"
import Click from "./click"
import Exposure from "./exposure"

// 实例化曝光和点击
const exp = new Exposure()
const cli = new Click()

Vue.directive("track", {
  bind(el, binding) {
    // 获取指令参数
    const { arg } = binding
    arg.split("|").forEach((item) => {
      // 点击
      if (item === "click") {
        cli.add({ el })
      } else if (item === "exposure") {
        exp.add({ el })
      }
    })
  },
})

同时需要在src/index.js引入即可:

import "./directives/track"

使用

在需要埋点的地方使用也是很简单的:

@@##@@

不足

通过Vue自定义指令的一个简单封装,业务代码和埋点代码就达到了一定的解耦,相较之前,无论是埋点的开发成本还是维护成本都降低了很多。

但是这也只是一个最简单的实现,还有很多情况需要考虑:

  • 曝光时频次很高,是否可以考虑批量上报?
  • 用户访问一半页面,突然切出,之后又重新进入,这种情况埋点又该如何上报?
  • 用户设备不支持Intersection ObserverAPI 情况,是否要考虑向下兼容?

鉴于这套埋点方案还在不断完善中,等后续完善并在业务中落地平稳运行后。我再分享其中的细节给到大家。

【相关视频教程推荐:vuejs入门教程web前端入门

前端怎么埋点?浅析vue自定义指令进行前端埋点的方法

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

2

2026.03.05

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

56

2026.03.04

AI安装教程大全
AI安装教程大全

2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

30

2026.03.04

Swift iOS架构设计与MVVM模式实战
Swift iOS架构设计与MVVM模式实战

本专题聚焦 Swift 在 iOS 应用架构设计中的实践,系统讲解 MVVM 模式的核心思想、数据绑定机制、模块拆分策略以及组件化开发方法。内容涵盖网络层封装、状态管理、依赖注入与性能优化技巧。通过完整项目案例,帮助开发者构建结构清晰、可维护性强的 iOS 应用架构体系。

59

2026.03.03

C++高性能网络编程与Reactor模型实践
C++高性能网络编程与Reactor模型实践

本专题围绕 C++ 在高性能网络服务开发中的应用展开,深入讲解 Socket 编程、多路复用机制、Reactor 模型设计原理以及线程池协作策略。内容涵盖 epoll 实现机制、内存管理优化、连接管理策略与高并发场景下的性能调优方法。通过构建高并发网络服务器实战案例,帮助开发者掌握 C++ 在底层系统与网络通信领域的核心技术。

25

2026.03.03

Golang 测试体系与代码质量保障:工程级可靠性建设
Golang 测试体系与代码质量保障:工程级可靠性建设

Go语言测试体系与代码质量保障聚焦于构建工程级可靠性系统。本专题深入解析Go的测试工具链(如go test)、单元测试、集成测试及端到端测试实践,结合代码覆盖率分析、静态代码扫描(如go vet)和动态分析工具,建立全链路质量监控机制。通过自动化测试框架、持续集成(CI)流水线配置及代码审查规范,实现测试用例管理、缺陷追踪与质量门禁控制,确保代码健壮性与可维护性,为高可靠性工程系统提供质量保障。

79

2026.02.28

Golang 工程化架构设计:可维护与可演进系统构建
Golang 工程化架构设计:可维护与可演进系统构建

Go语言工程化架构设计专注于构建高可维护性、可演进的企业级系统。本专题深入探讨Go项目的目录结构设计、模块划分、依赖管理等核心架构原则,涵盖微服务架构、领域驱动设计(DDD)在Go中的实践应用。通过实战案例解析接口抽象、错误处理、配置管理、日志监控等关键工程化技术,帮助开发者掌握构建稳定、可扩展Go应用的最佳实践方法。

61

2026.02.28

Golang 性能分析与运行时机制:构建高性能程序
Golang 性能分析与运行时机制:构建高性能程序

Go语言以其高效的并发模型和优异的性能表现广泛应用于高并发、高性能场景。其运行时机制包括 Goroutine 调度、内存管理、垃圾回收等方面,深入理解这些机制有助于编写更高效稳定的程序。本专题将系统讲解 Golang 的性能分析工具使用、常见性能瓶颈定位及优化策略,并结合实际案例剖析 Go 程序的运行时行为,帮助开发者掌握构建高性能应用的关键技能。

50

2026.02.28

Golang 并发编程模型与工程实践:从语言特性到系统性能
Golang 并发编程模型与工程实践:从语言特性到系统性能

本专题系统讲解 Golang 并发编程模型,从语言级特性出发,深入理解 goroutine、channel 与调度机制。结合工程实践,分析并发设计模式、性能瓶颈与资源控制策略,帮助将并发能力有效转化为稳定、可扩展的系统性能优势。

47

2026.02.27

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Vue 教程
Vue 教程

共42课时 | 9.2万人学习

Vue3.x 工具篇--十天技能课堂
Vue3.x 工具篇--十天技能课堂

共26课时 | 1.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号