埋点 · 数据上报

Analytics Tracker
使用指南

本文档面向业务开发者,说明如何在 Zoomex Web / Mobile 页面中接入埋点,涵盖 PV 上报、按钮点击、指令绑定与回调结果上报。

SDK @region-lib/[email protected] Nuxt 3 Plugin 更新 2026-05-26

所有埋点能力通过 Nuxt Plugin 注入,业务侧始终通过 useNuxtApp().$tracker 调用,不要直接 import SDK 函数。

火山引擎
window.collectEvent
data-finder SDK
@region-lib/data-finder
Nuxt Plugin
analytics-tracker.client.ts
业务代码
$tracker / v-tracker
Plugin 文件名以 .client.ts 结尾,仅在浏览器端运行。SSR 阶段访问 $tracker 会报错,埋点代码必须放在 onMounted 或客户端事件处理函数中。

1方法选择决策图

遇到埋点需求时,按此流程判断应该调用哪个方法。

需要埋点 什么类型的事件? 区分上报场景 进入页面 PV 上报 setTrackerInfo() → trackPageViewCollect() 接口返回 Callback 上报 trackCallbackCollect() ret_code + 业务字段 用户点击元素 点击后立即跳转页面? 路由 push / window.open 是,立即跳转 Beacon 防丢点 trackClickBeconCollect() sendBeacon 保证不丢点 否,留在当前页 模板有额外业务逻辑? 条件判断 / 动态传参 无,纯上报 v-tracker 指令 声明式绑定 click 事件 → trackClickCollect() 有业务逻辑 元素类型? button 还是 a 链接 button trackBtnClickCollect() { btn_name, btn_label, ...extra } 普通按钮 · 无需传 btn_type a / link trackLinkClickCollect() { btn_name, btn_label, ...extra } 超链接 · 无需传 btn_type
决策节点 PV 上报 Beacon 防丢点 Click 上报(三种) Callback 回调

2页面完整生命周期时序

一个页面从进入到操作到接口回调的完整上报流程,以及各步骤调用的方法。

页面 / Composable
$tracker
SDK (data-finder)
火山引擎
▶ onMounted — 页面挂载(仅客户端执行)
setTrackerInfo({ project_type, project_name })
startCollect(options)
↓ 写入全局上下文
trackPageViewCollect()
trackPageViewCollect()
✅ 上报 PageView
▶ 用户点击普通按钮(不跳转页面)
trackBtnClickCollect({
btn_name, btn_label, ...extra })
转发
trackBtnClickCollect()
✅ 上报 Click
▶ 用户点击卡片 / 链接(点击后立即跳转页面)
trackClickBeconCollect({
btn_name, btn_label, ...extra })
转发
sendBeacon(payload)
✅ Beacon 保证不丢
router.push('/next-page')
页面立即跳转,不阻塞
▶ 接口请求返回结果(try/catch 中处理)
trackCallbackCollect({
ret_code, result_status, ...extra })
转发
trackCallbackCollect()
✅ 上报 Callback

3API 速查

方法触发时机关键参数
setTrackerInfo(options)进入页面时,设置页面级公共属性project_type, project_name
trackPageViewCollect()紧跟 setTrackerInfo,上报 PV无参数
trackBtnClickCollect(options)普通按钮点击btn_name, btn_label, + 业务扩展字段
trackLinkClickCollect(options)超链接点击同上
trackClickBeconCollect(options)点击后立即跳转时,防丢点同上,内部使用 Beacon
trackCallbackCollect(options)接口响应后,上报成功/失败结果ret_code, + 业务扩展字段

4页面 PV 上报

每个页面的 onMounted 中,先调用 setTrackerInfo 设置当前页面上下文,再调用 trackPageViewCollect 触发 PV 事件。后续所有点击事件都会自动携带这里设置的 project_typeproject_name

TypeScriptpages/predict/index.vue — <script setup>
onMounted(() => {
  const { $tracker } = useNuxtApp()

  // 第一步:告诉 SDK 当前在哪个页面
  $tracker.setTrackerInfo({
    project_type: 'predict',       // 业务线,同一业务内固定
    project_name: 'predictCrypto',  // 页面唯一 ID
  })

  // 第二步:上报 PV(无参数)
  $tracker.trackPageViewCollect()
})
setTrackerInfo 每个页面只调一次,不要放在循环或每次点击里。它会覆盖全局上下文,如果在按钮点击里调用,可能污染后续其他事件的 project_name

5按钮点击上报

在点击处理函数中调用 trackBtnClickCollect先上报再执行业务逻辑

基础用法

TypeScriptcomponents/prediction/position/PositionTable.vue
function handleSellClick(item: PositionItem) {
  const { $tracker } = useNuxtApp()

  $tracker.trackBtnClickCollect({
    btn_name:     'sell_prediction_position',  // 唯一 ID,英文,不随文案变
    btn_label:    'Sell',
    market_id:    item.marketId,
    market_title: item.marketTitle,
  })

  openSellSheet(item)  // 上报完再执行业务
}

带枚举值的场景(Yes / No 方向)

TypeScript
function handleOptionClick(marketId: number, side: 'yes' | 'no') {
  const { $tracker } = useNuxtApp()
  $tracker.trackBtnClickCollect({
    btn_name:  'trade_market_option',
    btn_label: side === 'yes' ? 'Yes' : 'No',
    market_id: marketId,
    side:      side,
  })
}

6v-tracker 指令(声明式)

对于没有额外业务逻辑的点击元素,直接在模板里绑定 v-tracker 指令,比命令式更简洁。内部自动监听 click 事件并调用 trackClickCollect

HTML Template
<!-- button 元素会自动推断 btn_type="button" -->
<button
  v-tracker="{
    btn_name:  'join_community',
    btn_label: 'Join Community',
  }"
  @click="handleJoin"
>加入社区</button>

<!-- 非 button/a 标签需要手动传 btn_type -->
<div
  v-tracker="{
    btn_name:  'market_detail',
    btn_label: '',
    btn_type:  'card',  <!-- 显式指定 -->
    market_id: item.id,
  }"
  @click="goDetail(item)"
></div>

btn_type 自动推断规则

元素标签自动推断 btn_type需要手传?
<button>"button"
<a>"link"
banner_id 字段"banner"
<div> 等其他元素空字符串需要手传
指令 vs 命令式如何选择? 如果点击时只需要上报、无其他逻辑,用 v-tracker。如果点击时还需要条件判断、接口调用、传动态参数,用命令式 trackBtnClickCollect

7跳转前防丢点(Beacon)

普通的 trackBtnClickCollect 是异步的。如果点击后立即跳转页面,浏览器可能在请求发出前就卸载了页面,导致数据丢失。此时用 trackClickBeconCollect,它底层使用 navigator.sendBeacon 保证发送。

TypeScript❌ 错误写法(可能丢点)
function goDetail(id: number) {
  $tracker.trackBtnClickCollect({ btn_name: 'market_detail', btn_label: '' })
  router.push(`/predict/detail/${id}`)  // ← 立即跳转,埋点可能未发出
}
TypeScript✅ 正确写法(Beacon 保证)
function goDetail(id: number) {
  const { $tracker } = useNuxtApp()
  $tracker.trackClickBeconCollect({
    btn_name:  'market_detail',
    btn_label: '',
    market_id: id,
  })
  router.push(`/predict/detail/${id}`)
}

8接口回调结果上报

在买入 / 卖出等关键接口响应后,用 trackCallbackCollect 上报操作结果,ret_code = 0 表示成功,其余为失败。

TypeScriptcomposables/predict/usePredictBuy.ts
async function submitBuyOrder(params: IBuyParams) {
  const { $tracker } = useNuxtApp()
  try {
    const res = await apiBuyPosition(params)
    $tracker.trackCallbackCollect({
      ret_code:      res.code,     // 0 = 成功
      result_status: 'success',
      market_id:     params.marketId,
      side:          params.side,
      amount:        params.amount,
    })
  } catch (err: any) {
    $tracker.trackCallbackCollect({
      ret_code:      err?.code ?? -1,
      result_status: 'fail',
      market_id:     params.marketId,
    })
  }
}

9新页面完整模板

复制以下结构,替换 project_name 和事件名即可。推荐把埋点逻辑封装进 composable,页面文件保持干净。

TypeScriptcomposables/predict/usePredictCrypto.ts
export function usePredictCrypto() {
  // ── PV ──────────────────────────────────────────────
  onMounted(() => {
    const { $tracker } = useNuxtApp()
    $tracker.setTrackerInfo({ project_type: 'predict', project_name: 'predictCrypto' })
    $tracker.trackPageViewCollect()
  })

  // ── Click(普通按钮)─────────────────────────────────
  function trackCategorySwitch(category: 'crypto' | 'sports' | 'world') {
    const { $tracker } = useNuxtApp()
    $tracker.trackBtnClickCollect({
      btn_name:  'switch_market_category',
      btn_label: 'Crypto | Sports | World',
      category:  category,
    })
  }

  // ── Click(跳转卡片,用 Beacon)──────────────────────
  function trackCardClick(marketId: number, title: string) {
    const { $tracker } = useNuxtApp()
    $tracker.trackClickBeconCollect({
      btn_name:     'market_detail',
      btn_label:    '',
      market_id:    marketId,
      market_title: title,
    })
  }

  return { trackCategorySwitch, trackCardClick }
}

10常见错误

错误写法原因正确做法
setup() 顶层直接调埋点 SSR 阶段 $tracker 不存在,会报错 放进 onMounted 或事件处理函数中
每次点击都调 setTrackerInfo 覆盖全局上下文,污染其他事件的 project_name setTrackerInfo 只在进入页面时调一次
跳转前用 trackBtnClickCollect 页面卸载快,异步请求可能被 cancel 跳转场景改用 trackClickBeconCollect
漏传 btn_name BI 无法按事件聚合,数据无意义 btn_name 是最核心字段,任何 Click 事件必传
直接 import SDK 函数调用 绕过 Plugin 层,未来改底层会遗漏 始终通过 useNuxtApp().$tracker 调用