Vue手動(dòng)埋點(diǎn)設(shè)計(jì)的方法實(shí)例
目標(biāo)
- 使用簡(jiǎn)單;
- 減少代碼侵入性,不影響業(yè)務(wù)代碼閱讀
簡(jiǎn)述
- 埋點(diǎn)一般是按頁面來管理的;
- 埋點(diǎn)的事件類型一般分為:點(diǎn)擊、曝光和頁面的進(jìn)入和離開;
- 埋點(diǎn)的實(shí)質(zhì)就是在恰當(dāng)?shù)臅r(shí)機(jī)去發(fā)送請(qǐng)求,上送業(yè)務(wù)參數(shù)
按頁面管理埋點(diǎn)
在每個(gè)頁面目錄下創(chuàng)建events.js,管理當(dāng)前頁面的所有埋點(diǎn)事件。
為了減少埋點(diǎn)對(duì)業(yè)務(wù)代碼的影響,events.js中每個(gè)埋點(diǎn)的設(shè)置都是一個(gè)方法,可以在這個(gè)方法中處理數(shù)據(jù)得到埋點(diǎn)需要上送的數(shù)據(jù)。
該埋點(diǎn)設(shè)置的方法,返回一個(gè)埋點(diǎn)需要上送的參數(shù)的對(duì)象。
// src/views/PageA/events.js export default { // 按事件類型管理 CLICK: { back(ctx, data) { let { param1, param2 } = data; // ...處理傳入的數(shù)據(jù) return { eventValue: '返回', elementId: 'pageA-返回', // 需要上送的處理后的業(yè)務(wù)參數(shù) customData: { param1, param2 } }; } } }
遵循使用簡(jiǎn)單的原則,調(diào)用埋點(diǎn)
// src/views/PageA/index.vue this.$track('CLICK.back', data);
實(shí)現(xiàn)上面的調(diào)用
- 使用
require.context()
聚合各個(gè)頁面目錄下的埋點(diǎn)設(shè)置(events.js
)。 - 聚合后的埋點(diǎn)設(shè)置按頁面作為模塊管理,使用頁面文件夾名稱作為模塊名。
- 結(jié)合路由管理,可以獲得當(dāng)前頁面的埋點(diǎn)配置模塊名。
- 在Vue.prototype下新增一個(gè)
$track()
方法。
// src/events/index.js import router from '@/router'; const ctx = require.context('@/views', true, /events\.js/); const configs = {}; ctx.keys().reduce((configs, path) => { if (/\.\/(\w+?)\/events\.js/.test(path)) { const moduleName = RegExp.$1; // 第一個(gè)子項(xiàng) configs[moduleName] = resolveModule(moduleName, ctx(path)); } return configs; }, configs); function resolveModule(moduleName, module) { return Object.entries(module.default).reduce((all, [EVENT_TYPE, events]) => { all[EVENT_TYPE] = Object.keys(events).reduce((typeAll, key) => { typeAll[key] = buildTrackRequest( EVENT_TYPE.toLowerCase(), key, events[key] ); return typeAll; }, {}); }); } function buildTrackRequest(eventType, trackName, trackSetting) { return function trackRequest(...args) { // 看完后面再回過來看 if (typeof trackSetting !== 'function') { trackSetting = obj2fn(trackSetting); } // 執(zhí)行用戶定義的方法,返回埋點(diǎn)上送參數(shù) const [success, result] = invokeUserFn(trackSetting.bind(this, {})); if (!success) return result; // 傳入?yún)?shù),發(fā)送埋點(diǎn)請(qǐng)求 return tracker(result); } } export function track(eventPath, ...args) { let event = configs; let seg; const segs = eventPath.split('.'); // 2段式 沒有提供模塊名,則需要去路由配置上取 if (segs.length === 2) { const moduleName = router.currentRoute.meta?.eventModule; if (!moduleName) { throwError(`${eventPath} 沒有在路由配置中設(shè)置"meta.eventModule" 或者配置成3段式`); } event = event[moduleName]; } while ((seg = segs.shift())) event = event[seg]; if (!event) throwError(`${eventPath} 不存在`); // 給event綁定當(dāng)前調(diào)用環(huán)境 return event.call(this, ...args); } function throwError(err) { throw Error(`[Track Error] ${err}`); } export default function install(Vue) { Vue.prototype.$track = track; }
埋點(diǎn)設(shè)置支持對(duì)象形式
很多時(shí)候,可能不需要上送業(yè)務(wù)參數(shù),寫成一個(gè)對(duì)象更加簡(jiǎn)單。
{ CLICK: { back: { eventValue: '返回', elementId: 'pageA-返回', } } }
有時(shí)候只需要上送簡(jiǎn)單的業(yè)務(wù)字段,無需額外處理,也想使用對(duì)象的形式。
支持{{param1}}模板語法,同vue-template用法。(param1是埋點(diǎn)調(diào)用組件的屬性)
{ CLICK: { back: { eventValue: '返回', elementId: 'pageA-返回', customData: { param1: '{{param1}}' } } } }
將對(duì)象格式的埋點(diǎn)配置轉(zhuǎn)成方法形式的
const templateRE = /\{\{(.+?)\}\}/g; // 處理對(duì)象形式的埋點(diǎn)設(shè)置 function obj2fn(obj) { return function() { const that = this; // 處理模板字符串 (function resolveObj(obj) { Object.keys(obj).forEach(key => { const val = obj[key]; // 解析模板字符串 if (typeof val === 'string' && templateRE.test(val)) { obj[key] = val.replace(templateRE, (...match) => { // js嚴(yán)格模式下無法執(zhí)行with語法,以下是一種變通 return new Function(`with(this){return ${match[1]}}`).call(that); }); } // 遞歸處理 else if (isPlainObject(val)) resolve(val); }); })(obj); return obj; }; }
提供頁面級(jí)別的參數(shù)設(shè)置
很多時(shí)候一個(gè)頁面下的埋點(diǎn)都需要上送相同的參數(shù),如頁面名稱等。
提供beforeModuleEach和afterModuleEach兩個(gè)鉤子。
一般使用beforeModuleEach設(shè)置模塊(頁面)通用的埋點(diǎn)參數(shù),再合并單獨(dú)的埋點(diǎn)設(shè)置參數(shù),得到所有需要上送的參數(shù)。
function resolveModule(moduleName, module) { // 獲取`events.js`文件中設(shè)置的鉤子 const { beforeModuleEach, afterModuleEach } = module; // 獲取動(dòng)態(tài)設(shè)置鉤子 const { beforeHooks, afterHooks } = getHooksByModule(moduleName); beforeModuleEach && beforeHooks.unshift(beforeModuleEach); afterModuleEach && afterHooks.unshift(afterModuleEach); return Object.entries(module.default).reduce((all, [EVENT_TYPE, events]) => { all[EVENT_TYPE] = Object.keys(events).reduce((typeAll, key) => { typeAll[key] = buildTrackRequest( EVENT_TYPE.toLowerCase(), key, events[key], beforeHooks, afterHooks ); return typeAll; }, {}); }); }
總結(jié)
到此這篇關(guān)于Vue手動(dòng)埋點(diǎn)設(shè)計(jì)的文章就介紹到這了,更多相關(guān)Vue手動(dòng)埋點(diǎn)設(shè)計(jì)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue中的基礎(chǔ)過渡動(dòng)畫及實(shí)現(xiàn)原理解析
這篇文章主要介紹了Vue中的基礎(chǔ)過渡動(dòng)畫原理解析,需要的朋友可以參考下2018-12-12vue3中各種類型文件進(jìn)行預(yù)覽功能實(shí)例
在vue移動(dòng)端項(xiàng)目中經(jīng)常遇到這樣的需求,對(duì)一些上傳的附件可以點(diǎn)擊之后在線預(yù)覽,所以下面這篇文章主要給大家介紹了關(guān)于vue3中各種類型文件進(jìn)行預(yù)覽功能的相關(guān)資料,需要的朋友可以參考下2021-09-09Vue設(shè)置提示和警告彈出框?qū)崙?zhàn)案例
頁面中會(huì)有很多時(shí)候需要彈窗提示,下面這篇文章主要給大家介紹了關(guān)于Vue設(shè)置提示和警告彈出框的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-02-02Vue-cli集成axios請(qǐng)求出現(xiàn)CORS跨域問題及解決
這篇文章主要介紹了Vue-cli集成axios請(qǐng)求出現(xiàn)CORS跨域問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,2023-10-10vue中的H5移動(dòng)端項(xiàng)目?真機(jī)測(cè)試配置方式
這篇文章主要介紹了vue中的H5移動(dòng)端項(xiàng)目?真機(jī)測(cè)試配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09vue loadmore 組件滑動(dòng)加載更多源碼解析
這篇文章主要介紹了vue loadmore 組件滑動(dòng)加載更多源碼解析,需要的朋友可以參考下2017-07-07