UNPKG

vue-uv-tracker

Version:

用于捕获点击、搜索框回车搜索、路由切换等埋点数据并上报到服务器的Vue插件

179 lines (168 loc) 5.58 kB
/* * @Author: CaoZhongQian * @Date: 2023-01-27 22:11:21 * @LastEditors: CaoZhongQian * @LastEditTime: 2023-02-25 22:41:36 * @FilePath: \vue-tracking\src\index.js * @Description: 埋点数据上报Vue插件 */ (function () { var Axios = require('axios') var VueTracking = { // 产品名字 productName: 'unknown', // 用户名称 username: 'unknown', // 上报到后台存储的Http接口地址 reportUrl: '', // axios http客户端 reportClient: null, // 是否禁用上报 disabled: false, // 是否启用控制台打印 console: false, //vue-router实例 router: null, install: function (Vue, options) { this.productName = options.productName || this.productName this.username = options.username || this.username this.reportUrl = options.reportUrl || '' this.disabled = options.disabled || false this.console = options.console || false this.router = options.router this.reportClient = Axios.create({ baseURL: this.reportUrl, withCredentials: false, timeout: 3000 }) Vue.prototype.$sendTrack = (eventName, eventData) => { this.reportTrackingData(eventName, eventData); } //注册指令 Vue.directive('track', { bind: function (el, binding, vnode) { el.addEventListener(binding.arg || 'click', () => { const { eventName, eventData } = binding.value; vnode.context.$sendTrack(eventName, eventData); }); } }); //注册输入框回车搜索指令 Vue.directive('track-search', { inserted: function (el, binding) { el.addEventListener('keydown', function (event) { if (event.key === 'Enter') { const keyword = event.target.value; const eventName = binding.value; const eventData = { keyword: keyword, }; Vue.prototype.$sendTrack(eventName, eventData); } }); } }); if (this.router) { let router = this.router router.beforeEach((to, from, next) => { // 获取当前时间戳 const timestamp = new Date().getTime(); // 获取上一个界面的路由信息 const previousRoute = router.app.$route; // 如果存在上一个界面的路由信息,则计算停留时间 if (previousRoute) { const stayDuration = timestamp - router.app.$previousRouteLeaveTime; const eventName = 'routeChange'; const eventData = { from: previousRoute.path, fromName: (previousRoute.meta && previousRoute.meta.title) ? previousRoute.meta.title : previousRoute.name, to: to.path, toName: (to.meta && to.meta.title) ? to.meta.title : to.name, stayDuration: stayDuration, }; Vue.prototype.$sendTrack(eventName, eventData); } // 更新上一个界面的离开时间戳 router.app.$previousRouteLeaveTime = timestamp; next(); }); } Vue.prototype.$tracker = this Vue.prototype.$reportTrackingData = this.reportTrackingData }, /** * @description: 上报埋点数据 * @param {*} eventName 事件名 * @param {*} eventData 事件数据 * @return {*} */ async reportTrackingData(eventName, eventData) { try { const trackingData = this.getTrackingData(eventName, eventData) await this.report(trackingData) } catch (error) { console.log('处理埋点数据出错') console.log(error) } }, /** * @description: 生成埋点数据报文 * @param {*} eventName * @param {*} eventData * @return {*} */ getTrackingData(eventName, eventData) { return { product: this.productName, username: this.username, href: window.location.href, eventName: eventName, eventData: eventData } }, /** * @description: 上报埋点数据到后台服务 * @param {*} trackingData * @return {*} */ async report(trackingData) { if (!this.disabled) { try { // 将数据序列化单行字符串,保证body体的json到了nginx是单行的json内容,解决filebeat解析多行文本失败的BUG const exceptionStr = JSON.stringify(trackingData) await this.reportClient({ method: 'post', data: exceptionStr, headers: { 'Content-Type': 'application/json' } }) } catch (error) { console.log('上报埋点数据出错') console.log(error) } } }, /** * @description: 设置上报的用户信息,用于标识异常信息来自哪个用户 * @param {*} username * @return {*} */ setUserName(username) { this.username = username } } if (typeof exports === 'object') { module.exports = VueTracking } else if (typeof define === 'function' && define.amd) { define([], function () { return VueTracking }) } else if (window.Vue) { window.VueExceptionCaptor = VueTracking Vue.use(VueTracking) } })()