mfc多文件過載onfilenew_PHP的過載-使用魔術方法實現
埋點方案的確定,業界的埋點方案主要分為以下三類:
程式碼埋點:在需要埋點的節點呼叫介面,攜帶資料上傳。如百度統計等;
視覺化埋點:使用視覺化工具進行配置化的埋點,即所謂的「無痕埋點」,前端在頁面載入時,可以讀取配置資料,自動呼叫介面進行埋點。如開源的Mixpanel;
無埋點:前端自動採集全部事件並上報埋點資料。如國內的神策資料等;
在當時排期緊湊,人力緊缺的情況下,顯然不允許我們去開發視覺化埋點方案和無埋點方案,所以只能採取程式碼埋點方案。
命令式埋點
命令式埋點,顧名思義,開發者需要手動在需要埋點的節點處進行埋點。如點選按鈕或連結後的回撥函式、頁面ready時進行請求的傳送。大家肯定都很熟悉這樣的程式碼:
// 頁面載入時傳送埋點請求
$(document).ready(function(){
// ... 這裡存在一些業務邏輯
sendRequest(params);
});
// 按鈕點選時傳送埋點請求
$('button').click(function(){
// ... 這裡存在一些業務邏輯
sendRequest(params);
});
可以很容易發現,這樣的做法很有可能會將埋點程式碼侵入業務程式碼,這使整體業務程式碼變得繁瑣,容易出錯,且後續程式碼會愈加膨脹,難以維護。所以,我們需要讓埋點的程式碼與具體的業務邏輯解耦,即 宣告式埋點 ,從而提高埋點的效率和程式碼的可維護性。
宣告式埋點
理論上,宣告式埋點只需要關注兩個問題:需要埋點的DOM節點;所需攜帶的資料
因此,可以很快想出一個宣告式埋點的方法:
// key表示埋點的唯一標識;act表示埋點方式
<button data-stat="{key:'111', act: 'click'}">埋點</button>
那麼可以去遍歷DOM樹,找到 [data-stat] 的節點,給這個button綁上click事件,把這些引數在回撥函式中通過請求發出去。
在DOM節點(html)上宣告埋點,與業務邏輯(通常在JavaScript檔案中)就解耦了。呼叫也很方便。
看起來很美,但這樣就能解決問題了嗎?顯然是不夠的。還需要解決以下問題:
遍歷DOM樹的時機問題,一個簡單的例子,一個表格的行資料是通過非同步載入,而表格行中的操作按鈕需要埋點,那麼在DOM ready的時候去遍歷,顯然是無法找到的
繫結埋點事件次數的問題,怎樣保證埋點事件不會被重複繫結到元素上,一次操作發了N個埋點請求?
如何處理特有的埋點行為,如頁面展現埋點,區域展現埋點?
如何在解綁時,銷燬已繫結的事件?
1.自定義指令實現埋點資料統計
在專案中通常需要做資料埋點,這個時候,使用自定義指令將會變非常簡單
在專案入口檔案 main.js中配置我們的自定義指令
// 坑位埋點指令
vue.directive('stat', {
bind(el, binding) {
el.addEventListener('click', () => {
const data = binding.value;
let prefix = 'store';
if (OS.isAndroid || OS.isPhone) {
prefix = 'mall';
}
analytics.request({
ty: `${prefix}_${data.type}`,
dc: data.desc || ''
}, 'n');
}, false);
}
});
2.使用路由攔截統計頁面級別的 PV
由於第一次在單頁應用中嘗試資料埋點,在專案上線一個星期之後,資料統計後臺發現,首頁的 PV 遠遠高於其它頁面,資料很不正常。後來跟資料後臺的人溝通詢問他們的埋點統計原理之後,才發現其中的問題所在。
傳統應用,一般都在頁面載入的時候,會有一個非同步的js載入,就像百度的統計程式碼類似,所以我們每個頁面的載入的時候,都會統計到資料;然而在單頁應用,頁面載入初始化只有一次,所以其它頁面的統計資料需要我們自己手動上報
解決方案
使用vue-router 的 beforeEach 或者 afterEach 鉤子上報資料,具體使用哪個最好是根據業務邏輯來選擇。
const analyticsRequest = (to, from) => {
// 只統計頁面跳轉資料,不統計當前頁 query 不同的資料
// 所以這裡只使用了 path, 如果需要統計 query 的,可以使用 to.fullPath
if (to.path !== from.path) {
analytics.request({
url: `${location.protocol}//${location.host}${to.path}`
});
}
};
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// 這裡做登入等前置邏輯判斷
// 判斷通過之後,再上報資料
...
analyticsRequest(to, from);
} else {
// 不需要判斷的,直接上報資料
analyticsRequest(to, from);
next();
}
});
在元件中使用我們的自定義指令
<section>
<div class="cm-btn feedback-btn cm-ft-l " @click='back' x-vflow="{val:'FeedBackBack',desc:'使用者點選了意見反饋返回按鈕'}">返回
</div>
</section>
基於 jquery + widget 的老專案
那麼在這些專案中的DOM操作是jquery甚至原生DOM API來實現,Vue的自定義指令就無法工作
資源搜尋網站大全 https://www.renrenfan.com.cn 廣州VI設計公司https://www.houdianzi.com
基於MutationObserver API的Mixin
MutationObserver是在DOM3標準中提出的標準API,提供讓開發者感知到在某一個DOM節點變更的能力。可以監聽以下場景:
-
childList: 目標節點的子節點插入刪除引起的變更
-
attributes: 目標節點屬性改變引起的變更
-
characterData: 目標節點的文字節點改變引起的變更,如通過appendData()等
-
subtree: 目標節點的子孫節點改變引起的變更
-
attributeOldValue:當attribute監聽被設定為true時,可以記錄改變前的屬性值
-
characterDataOldValue:當characterData監聽被設定為true時,可以記錄改變前的屬性值
-
attributeFilter:可以設定需要監聽的屬性列表
但為了保證MutationObserver可以在所有瀏覽器上正常工作,我們仍然引入了這個API的polyfill,詳情可見這裡。
在此能力的前提下,我們就可以在任意的DOM操作下觸發Vue進行重新解析指令。
我們將 MutationObserver 封裝進一個 Vue mixin , 非Vue應用的業務程式碼只需要引入這個mixin,這樣也可以很好地解耦。
詳細的實現原理可以見以下虛擬碼:
let observer;
export default {
ready() {
// 開啟監聽
observer = new MutationObserver(mutations => {
this.$compile(this.$el);
});
observer.observe(this.$el, config);
},
destroyed() {
// 清理工作
observer.disconnect();
observer.takeRecords();
}
}