Vue 接入(@tripo3d/lens/vue)
在 Vue 里做埋点,最直接的方式是把坐标、事件、参数写成元素上的 data-trace* 字符串属性——核心的 行为埋点 · autoTrack 会在点击 / 曝光触发那一刻用 getAttribute 读取它们。这套属性是纯 DOM 契约,Vue 的原生 :(v-bind)绑定就能写入,响应式变量会随重渲染自动刷新到属性上,不需要任何适配器。
@tripo3d/lens/vue 是这套契约之上的可选 DX 层:把「逐属性绑定 + params 序列化 + 循环引用兜底 + 属性清理」打包成 v-trace 指令,并补上命令式逃生口(useTrace() / this.$trace)。本文先讲不装适配器的原生写法,再讲初始化,最后才是适配器带来的便利。
先看用法:原生绑定写 data-trace*
声明式采集只认 DOM 上的 data-trace* 字符串属性——点击 / 曝光触发时才用 getAttribute 读取,SDK 本身不理解、也不需要理解响应式。所以在 Vue 里你完全可以不装适配器,直接写属性:坐标固定就用静态 HTML 属性,需要动态就用原生 :(v-bind)绑定。
<script setup lang="ts">
import { ref } from 'vue';
import { TraceEvent } from '@tripo3d/lens'; // 事件枚举:避免硬编码 'click' / 'expose'
const sku = ref('A1');
const tab = ref('docs');
</script>
<template>
<!-- 1. 纯静态:坐标固定,直接写 HTML 属性 -->
<button data-trace-key="home.banner.buy" data-trace-type="click">
购买
</button>
<!-- 2. 动态 params + 枚举多事件:用 : 绑定,对象须自己 JSON.stringify -->
<button
data-trace-key="home.banner.buy"
:data-trace-type="[TraceEvent.Click, TraceEvent.Expose].join(' ')"
:data-trace-params="JSON.stringify({ sku })"
>
购买
</button>
<!-- 3. 坐标拼接:祖先 data-trace 段 + 叶子 data-trace-key,动态段用 : 绑定 → home.nav.docs -->
<section data-trace="home">
<a data-trace="nav" :data-trace-key="tab" data-trace-type="click">
文档
</a>
</section>
</template>为什么 : 绑定能拿到响应式
响应式的解析发生在 Vue 写入侧:每次组件渲染时 Vue 求值绑定表达式(ref 在此自动 unref 成快照),在 patch 阶段写进 DOM 属性;采集器在触发那一刻读属性,读到的始终是「已解析好且刚刷新过」的最新快照。整条链路无需 SDK 碰响应式。绑定值为 null / undefined 时 Vue 会自动移除该属性,无需手动清理。
要点(规则与手写 HTML 完全一致,详见 行为埋点 · 声明式埋点):
- 锚点:元素必须带
data-trace或data-trace-key才会被采集;单独写data-trace-type/data-trace-params不会触发。拼出的坐标须为合法 TracePath(2–8 段),否则静默丢弃。 - 事件:
data-trace-type缺省为click;多事件用空格分隔("click expose")。token 可从@tripo3d/lens引入TraceEvent常量避免硬编码——绑定场景写:data-trace-type="TraceEvent.Click",多事件写:data-trace-type="[TraceEvent.Click, TraceEvent.Expose].join(' ')"。但请注意:手写属性的值类型是string,享受不到v-trace的on字段那样的类型约束(拼错不报错),想要类型安全请用v-trace。 - 参数:
data-trace-params是三者中唯一需要序列化的——:绑定必须传字符串,直接绑对象会被写成"[object Object]"导致解析失败(见下方警告)。坐标(data-trace/data-trace-key)与事件(data-trace-type)都是字符串,直接写即可。
:data-trace-params 不要直接绑对象
:data-trace-params="{ sku }" 会被 Vue 的 setAttribute 转成字符串 "[object Object]"(DOM 属性只能存字符串,Vue 只做 toString、不做 JSON 序列化),采集端 JSON.parse 失败、参数丢失。必须写成 :data-trace-params="JSON.stringify({ sku })"。另外手写 JSON.stringify 遇到循环引用会直接抛错、可能中断渲染,需自行 try/catch——v-trace 已内置这层兜底。
属性写了不等于会上报
上面的写法只是把 data-trace* 落到了 DOM。真正的点击委托与曝光登记,需要一个已初始化、且开启 autoTrack 的核心实例——见下一节。
让埋点生效:初始化核心实例
data-trace* 属性要被采集上报,前提是页面里已经 new TripoLens 并 init(),且装了 TrackingPlugin({ autoTrack: true })。这一步与「用不用适配器」无关,是所有方案的共同前提,只依赖核心包 @tripo3d/lens。
pnpm add @tripo3d/lensnpm install @tripo3d/lensyarn add @tripo3d/lensnew TripoLens() 出来就是个普通对象,与框架无关。用一个模块导出存起来,声明式采集即可全局生效,命令式 API 也随处可 import:
// lib/trace.ts
import { TripoLens, TrackingPlugin } from '@tripo3d/lens';
// 尽早构造(快照入口 URL);autoTrack 必开,声明式采集才会启动
export const trace = new TripoLens({
// event_format App 段
app: 'shop',
// 远端 CDN 配置 URL
configUrl: 'https://cdn.example.com/lens/config.json',
// 完整上报地址,由业务方给定
endpoint: 'https://collect.example.com/report',
plugins: [
new TrackingPlugin({ autoTrack: true })
],
});
await trace.init();在 main.ts 里 import 一次这个模块(或直接在入口构造),确保它在应用挂载前执行:
// main.ts
import { createApp } from 'vue';
import App from './App.vue';
import './lib/trace'; // 触发构造 + init;纯声明式项目到这里就够了
createApp(App).mount('#app');适配器不托管实例
与 Nuxt 适配器(模式 A 可自动创建客户端实例)不同,Vue 适配器只注册指令、不构造也不 init 实例。渠道归因要求实例在业务任何 URL 操作之前构造,所以你需自己尽早 new TripoLens(快照入口 URL)——放在 lib/trace.ts 顶层并尽早 import 即可。
构造实例的必填参数
new TripoLens(params) 在构造期即校验 app / configUrl / endpoint 三项,缺任一直接抛错(无内置默认值);其余如 plugins、beforeEmit、onError、fetch 等均为可选,行为/错误/性能采集为 opt-in、需经 plugins 追加对应插件。各参数的类型、归一化与校验规则见 构造参数,初始化时序见 初始化。
埋点依赖 autoTrack
无论手写 data-trace* 还是用 v-trace,真正的点击委托与曝光登记都由 TrackingPlugin({ autoTrack: true }) 内的声明式采集器完成。不开 autoTrack,属性会照写但无人采集。
可选:Vue 适配器与声明式 v-trace
到这里,纯手写 data-trace* 已经能覆盖全部采集能力——响应式、SSR、曝光时序都不缺。适配器要解决的只是手写的重复与易错:逐属性绑定、params 的 JSON.stringify、循环引用兜底、属性清理。装上它,一句 v-trace 绑定即可替代多个属性;再加命令式逃生口(useTrace() / this.$trace),让声明式、命令式两种用法都更省心。
Vue 适配层已折入 core,作为 @tripo3d/lens 的子路径 @tripo3d/lens/vue 直接导出,无需单独安装适配器包。
core(@tripo3d/lens)把 vue(^3.3)声明为 optional peerDependency,请确保工程内已安装。在 main.ts 里以 app.use 注册适配器,并把上一节构造的实例传入:
// main.ts
import { createApp } from 'vue';
import { TripoLensVue } from '@tripo3d/lens/vue';
import App from './App.vue';
import { trace } from './lib/trace'; // 上一节构造好的实例
createApp(App).use(TripoLensVue, { trace }).mount('#app');用 v-trace 声明式埋点
v-trace 的绑定值是 data-trace* 的对象化表达,支持响应式变量(变更后重渲染自动刷新属性)。绑定为字符串时按扁平 path 处理;为对象时显式指定字段:
<script setup lang="ts">
import { ref } from 'vue';
import { TraceEvent } from '@tripo3d/lens/vue'; // 事件枚举一并 re-export
const sku = ref('A1');
const tab = ref('docs');
</script>
<template>
<!-- 祖先段 v-trace="{ path: home }":叶子坐标自动前置 -->
<section
v-trace="{
path: 'home'
}"
>
<!-- 叶子 key + 单事件 → home.buy -->
<button
v-trace="{
key: 'buy',
on: 'click',
params: { sku },
}"
>
购买
</button>
<!-- 多事件(click + expose) -->
<button
v-trace="{
key: 'card',
on: [TraceEvent.Click, TraceEvent.Expose],
params: { sku },
}"
>
卡片
</button>
</section>
<!-- 独立扁平 path(响应式插值) -->
<a
v-trace="{
path: `home.nav.${tab}`,
on: [TraceEvent.Click, TraceEvent.Expose],
}"
>
文档
</a>
</template>| 绑定字段 | 映射属性 | 说明 |
|---|---|---|
key | data-trace-key | 叶子末段,与祖先链 data-trace 组合成完整坐标 |
path | data-trace | 扁平坐标或祖先段 |
on | data-trace-type | 触发事件,缺省 click;可传数组多事件;用 TraceEvent 枚举或字符串字面量 |
params | data-trace-params | 上报参数,支持响应式;序列化失败(循环引用等)走插件 onError |
exposePolicy | data-trace-expose-policy | 元素级曝光去重策略,用 ExposePolicy 枚举取值(如 ExposePolicy.OncePerElement 列表项各报一次),免手拼字符串 |
坐标拼接、tripo 前缀、曝光去重等规则与手写 data-trace 一致,详见 行为埋点 · 声明式埋点。ExposePolicy 枚举与 TraceEvent 一样由 @tripo3d/lens/vue re-export(也可从 @tripo3d/lens 导入)。
手写 vs v-trace:该用哪种
| 场景 | 推荐 |
|---|---|
| 坐标固定、无动态参数 | 直接写静态 data-trace*,最轻 |
有动态 params / 动态坐标段 | v-trace(自动 JSON.stringify + 循环引用兜底 + 多属性映射);或原生 : 绑定 + 手动 JSON.stringify |
想要模板内联、不占用元素的 v-bind 通道 | v-trace |
简言之:手写 data-trace*(含 : 绑定)在能力上等价于 v-trace,响应式、SSR、曝光时序都不缺;区别只在 DX——v-trace 把「逐属性绑定 + params 序列化 + 循环引用兜底 + 属性清理」打包掉,动态参数场景更省心、更不易错。
纯 HTML / 原生 JS 场景
不在 Vue 里(服务端模板、静态站、原生 JS)也能用同一套 data-trace*:直接写属性、用 setAttribute / dataset 动态更新即可,用法见 行为埋点 · 声明式埋点。
命令式埋点
命令式 API(track / identify / captureException …)都挂在 TripoLens 实例上,所以分两步:先拿到实例,再调用。
拿到实例的两种方式
按项目形态选其一。
路径一:自己管实例(最简,CSR 首选)
上一节的 lib/trace.ts 导出的实例与框架无关,哪儿都能 import——纯函数、组件、工具库都行:
// 任意文件直接调用,不经过任何插件
import { trace } from '@/lib/trace';
// 上报标记为track类型
trace.track('pay.done', { orderId });
// 需要其他上报类型
trace.click('pay.button')
trace.expo('pay.button')这条路完全不经过插件:既不用给 app.use 传 trace,声明式 v-trace 也照常工作(指令只写 data-trace* 属性、采集靠核心 autoTrack,本就不需要实例)。换句话说——手动初始化后实例就已经全局可用,用户自管即可。
路径二:交给插件注入(要逃生口 / DI / SSR 时)
把实例传给插件(即上一节的 app.use(TripoLensVue, { trace })),组件内改用框架风格的逃生口(useTrace() / this.$trace)拿:
app.use(TripoLensVue, { trace }); // 传入后组件内 useTrace() / this.$trace 才可用仅在以下情况才需要走这条路:
| 需求 | 为什么要把实例传给插件 |
|---|---|
| 框架风格逃生口 | 不想在组件里硬 import 模块变量,改用 useTrace() / this.$trace 从注入体系拿 |
Vue 的 app.use 与 React 的 <TraceProvider> 是同一件事
两者对等,都只做一件事——把实例放进框架的依赖注入体系,好让组件内的逃生口拿到。区别只在 API 形态:Vue 有 app.use(plugin, options) 全局插件机制,根注入一次即可;React 没有等价的全局机制,跨层级共享靠 Context,所以改用 <TraceProvider> 包裹应用根。详见 React 接入。
调用命令式 API
走路径二注入后,经逃生口拿到实例即可上报:
// 组合式 API
import { useTrace } from '@tripo3d/lens/vue';
const trace = useTrace(); // 未安装插件或未传 trace 时抛错
trace.track('checkout.submit', { amount: 99 });// 选项式 API:this.$trace(未传 trace 时为 undefined,故判空调用)
this.$trace?.track('checkout.submit', { amount: 99 });this.$trace 的类型已由适配器通过 declare module 'vue' 自动增广,无需在工程内手写声明。命令式方法的语义见 行为埋点 · 命令式埋点;曝光进阶 trackImpression / setExposurePolicy 同样挂在实例上,见 行为埋点 · 进阶。
SSR
指令实现了 getSSRProps,data-trace* 会随服务端 HTML 直出,hydration 后即可被采集,无需额外接线。服务端采集(性能 / 错误)机制见 SSR 采集;若用 Nuxt,优先用 Nuxt 适配器 自动接线。
插件选项
app.use(TripoLensVue, options):
| 选项 | 类型 | 默认 | 说明 |
|---|---|---|---|
trace | TripoLens? | — | 已构造(建议已 init)的实例;提供后才有 useTrace() / this.$trace |
name | string? | 'trace' | 指令名,决定模板里写 v-<name>(默认即 v-trace) |
onError | (err) => void | — | params 序列化失败回调(坐标仍保留,仅丢 params) |
除插件外,@tripo3d/lens/vue 还导出 TRACE_KEY(InjectionKey<TripoLens>,供不走 useTrace()、需要手动 inject 的场景)与 createTraceDirective(options?)(不经插件、手动 app.directive 注册指令的口子)。
故障排查
| 症状 | 原因 | 处理 |
|---|---|---|
| 埋点不上报,控制台无报错 | 没开 autoTrack,属性写了但无人采集 | 构造时加 new TrackingPlugin({ autoTrack: true }) |
useTrace() 抛错 | 未 app.use(TripoLensVue),或安装时未传 trace | 注册插件并传入实例 |
this.$trace 是 undefined | 安装时未传 trace | 在 app.use 的 options 里传 trace |
| 点击有上报、曝光没有 | 曝光阈值 / 去重策略 | 见 曝光去重策略 与 AutoTrackOptions.exposeThreshold |