埋点 · 数据上报
Analytics Tracker
使用指南
本文档面向业务开发者,说明如何在 Zoomex Web / Mobile 页面中接入埋点,涵盖 PV 上报、按钮点击、指令绑定与回调结果上报。
所有埋点能力通过 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 上报
Beacon 防丢点
Click 上报(三种)
Callback 回调
2页面完整生命周期时序
一个页面从进入到操作到接口回调的完整上报流程,以及各步骤调用的方法。
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_type 和 project_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 调用 |