一、初始化sdk配置
window._jt_ = window.jimoTracker = new Tracker({
env_name: process.env.APP_ENV || 'test', // 环境名称 dev,test,test2,test3,uat,prod
node_env: process.env.NODE_ENV || 'production', // 环境变量 production,development
enableBodyClick: true, // 开启事件委托
enableBlockExposure: true, // 开启模块曝光
enableHideElementExposure: true, // 开启隐藏元素曝光
});
二、初始化主对象
this._mainObj = {
env_name: options.env_name, // dev,test,test2,test3,uat,prod
device_id: '', // 设备浏览器id
open_id: '',
union_id: '',
user_id: '', // 企微后台用户userId
main_id: '', // 我们后台区别用户
user_type: '', // 用户类型:企业员工、企业客户、潜在客户、游客
identity: '', // 身份类型 非同事,同事,员工自己
corp_id: '',
staff_id: '',
sub_session_id: '', // 隐藏后重新显示 会话子id
event_type: '', // 事件类型
page_desc: '', // 当前页面路径
block_desc: '', // 模块
button_desc: '', // button
parameters: {}, // 附加参数
};
三、jimo-sdk传入数据
_jt_.setData(obj); // jimo-sdk传入数据
public setData(obj: MainObj) {
this._mainObj = { ...this._mainObj, ...obj, parameters: { ...this._mainObj.parameters, ...obj.parameters } };
}
四、冷启动发送埋点
_jt_.coldStart(); // 执行冷启动
public coldStart() {
const start_source = this._mainObj.start_source;
if (start_source) {
this.sendTracker({
event_type: 'cold_start',
});
}
}
五、淘宝SPM超级定位模型
六、手动埋点
_jt_.sendTracker({
event_type: 'page_exp',
block_desc: '',
button_desc: '',
parameters: { objId },
});
public sendTracker(data: Data) {
const trackData = { ...this._mainObj, ...data, parameters: { ...this._mainObj.parameters, ...data.parameters } };
window.trackInfo(trackData);
}
七、属性埋点,body添加事件委托监听
data-jt-sender={JSON.stringify({
event_type: 'popup_window',
block_desc: 'tel_page',
button_desc: 'enter_btn',
parameters: { objId },
})}
document.body.addEventListener('click', (e: any) => {
let target = e.target;
const spmObj: any = {};
while (target && target.dataset) {
target.dataset.jtSpmb && (spmObj.page_desc = target.dataset.jtSpmb);
target.dataset.jtSpmc && (spmObj.block_desc = target.dataset.jtSpmc);
target.dataset.jtSpmd && (spmObj.button_desc = target.dataset.jtSpmd);
target.dataset.jtSender && (spmObj.jtSender = target.dataset.jtSender);
// 向上冒泡
target = target.parentNode;
}
if (spmObj.jtSender) {
const data = JSON.parse(spmObj.jtSender);
// 优先使用业务参数data,其次spmObj
const newSpmObj = {
page_desc: spmObj.page_desc,
block_desc: spmObj.block_desc,
button_desc: spmObj.button_desc,
};
ctx.sendTracker({ ...newSpmObj, ...data });
}
});
八、模块曝光
<div
data-jt-block-exposure={JSON.stringify(data)}
ref={_jt_.refreshBlockExposure}
>
{children}
</div>
/**
* 建立模块曝光观察者
*/
ctx._blockExposureObserver = new IntersectionObserver(
(changes) => {
changes.forEach((change: any) => {
if (change.intersectionRatio < 0.5) return;
ctx.sendTracker(handleDomSpmCache(ctx, change));
});
},
{ threshold: 0.5 }
);
/**
* 刷新模块曝光
*/
export function refreshBlockExposure(this: any) {
clearTimeout(this._blockExposureTimer); // 防抖
this._blockExposureTimer = setTimeout(() => {
this._blockExposureObserver.disconnect();
const doms = document.querySelectorAll('[data-jt-block-exposure]');
doms.forEach((item) => {
this._blockExposureObserver.observe(item);
});
}, 500);
}
/**
* 查找spm缓存信息
*/
tracker._domSpmCache = new WeakMap(); // dom的spm位置信息缓存,dom移除或切换页面自动清除
const handleDomSpmCache = (ctx, change) => {
let target = change.target;
let spmObj: any = {};
const alreadyDatasetObj = ctx._domSpmCache.get(change.target);
if (!alreadyDatasetObj) {
while (target && target.dataset) {
target.dataset.jtSpmb && (spmObj.page_desc = target.dataset.jtSpmb);
target.dataset.jtSpmc && (spmObj.block_desc = target.dataset.jtSpmc);
target.dataset.jtSpmd && (spmObj.button_desc = target.dataset.jtSpmd);
// 向上冒泡
target = target.parentNode;
}
ctx._domSpmCache.set(change.target, spmObj);
} else {
spmObj = alreadyDatasetObj;
}
const data = JSON.parse(change.target.dataset.jtBlockExposure);
// 优先使用业务参数data,其次spmObj
return { ...spmObj, ...data };
};
九、隐藏元素曝光
<div
data-jt-hide-element-exposure={JSON.stringify(data)}
ref={_jt_.refreshHideElementExposure}
/>
/**
* 建立隐藏元素曝光观察者
*/
ctx._hideElementExposureObserver = new IntersectionObserver((changes) => {
changes.forEach((change: any) => {
if (change.intersectionRatio <= 0) return;
ctx.sendTracker(handleDomSpmCache(ctx, change));
});
});
/**
* 刷新隐藏元素曝光
*/
if (!this._options.enableHideElementExposure) return;
clearTimeout(this._hideElementExposureTimer); // 防抖
this._hideElementExposureTimer = setTimeout(() => {
this._hideElementExposureObserver.disconnect();
const doms = document.querySelectorAll('[data-jt-hide-element-exposure]');
doms.forEach((item) => {
this._hideElementExposureObserver.observe(item);
});
}, 200);
十、react通用埋点组件
<Tracker
type="block" // click clickAndSpm spm block hide
data={{
event_type: 'block_exp',
block_desc: '',
button_desc: '',
parameters: { objId: newsPaperSensorsData.properties.paper_id },
}}
>{'被包裹的模块'}</Tracker>
/**
* Tracker组件
*/
export default function Tracker({ type = 'click', tagName = 'div', ...args }: TrackerProps) {
const newProps = {
...args,
tagName,
data: { ...args.data, type },
};
return handleTypeFn[type](newProps);
}
/**
* type策略类型(放组件外面减少组件编译后代码量)
*/
const handleTypeFn = {
// 点击埋点
click: ({ data, children, tagName, className, display, ...args }: TrackerProps) => {
return React.createElement(
tagName,
{
'data-jt-sender': JSON.stringify(data),
className: handleClassName(className, display),
...args,
},
children
);
},
// 模块曝光
block: ({ data, children, tagName, className, display, ...args }: TrackerProps) => {
return React.createElement(
tagName,
{
'data-jt-block-exposure': JSON.stringify(data),
ref: _jt_.refreshBlockExposure,
className: handleClassName(className, display),
...args,
},
children
);
},
};