1/** 2 * è½»éçº§ç¨æ·è¡ä¸ºè¿½è¸ªèæ¬ 3 * åè½ï¼ä¸æ¥é¡µé¢è®¿é®(visit)ä¸æææ´»è·(active)äºä»¶ 4 * åç½®æ¡ä»¶ï¼å¿ é¡»åå¨ cookie "utm_track" æä¼è§¦åä»»ä½ä¸æ¥ 5 * æ´»è·å¤å®æ¡ä»¶ï¼æ»¡è¶³ä»»ä¸å³å¯ï¼ï¼ç¹å» / æ»å¨ / è·¯ç±åå / åçâ¥30s 6 */ 7;(function () { 8 // SSR ç¯å¢å®å ¨æ£æ¥ï¼é¿å 卿å¡ç«¯æ§è¡æ¶æ¥é 9 if (typeof window === 'undefined' || typeof document === 'undefined') return; 10 11 // 没æ utm_track æ è¯ï¼ç´æ¥éåºï¼ä¸ç»å®ä»»ä½äºä»¶ãä¸åä»»ä½è¯·æ± 12 if (!getCookie('utm_track')) return; 13 14 // ==================== é 置常é ==================== 15 /** 访é®ä¸æ¥æ¥å£ */ 16 const VISIT_API = `${webDomain}/api/utm/visit`; 17 /** æ´»è·ä¸æ¥æ¥å£ */ 18 const ACTIVE_API = `${webDomain}/api/utm/active`; 19 /** å¤å®ä¸ºæææ´»è·çæä½åçç§æ° */ 20 const ACTIVE_STAY_SECONDS = 30; 21 22 // ==================== ç¶æåé ==================== 23 /** 访é®äºä»¶æ¯å¦å·²ä¸æ¥ï¼æ¯ä¸ªé¡µé¢çå½å¨æä» 䏿¬¡ï¼ */ 24 let hasVisitReported = false; 25 /** æ´»è·äºä»¶æ¯å¦å·²ä¸æ¥ï¼æ¯ä¸ªé¡µé¢çå½å¨æä» 䏿¬¡ï¼ */ 26 let hasActiveReported = false; 27 /** 页é¢è¿å ¥æ¶é´æ³ï¼msï¼ï¼ç¨äºè®¡ç®åçæ¶é¿ */ 28 const enterAt = Date.now(); 29 /** åçæ¶é¿å®æ¶å¨ IDï¼ç¨äºå¨é¡µé¢éæ¯æ¶æ¸ ç */ 30 let stayTimer = null; 31 /** æ»å¨äºä»¶æ¯å¦å·²è§¦åè¿ï¼ä» 馿¬¡æ»å¨è§¦åæ´»è·ä¸æ¥ï¼ */ 32 let scrollTriggered = false; 33 /** 声æç¼ååé */ 34 let cachedBody = null; 35 36 // ==================== ç½ç»è¯·æ±å·¥å · ==================== 37 38 /** 39 * éè¿ fetch åé POST JSON è¯·æ± 40 * @param {string} url - ç®æ æ¥å£å°å 41 * @returns {Promise<boolean>} è¯·æ±æ¯å¦æå 42 */ 43 async function postJSON(url) { 44 try { 45 const data = await formatParams(); 46 47 await $.ajax({ 48 url, 49 data, 50 type: 'POST', 51 xhrFields: { withCredentials: true}, // å 许åé Cookie 52 crossDomain: true, // æç¡®è·¨åè¯·æ± 53 }); 54 55 // 䏿¥æååæ´æ°ç¼å 56 cachedBody = data; 57 return true; 58 } catch { 59 return false; 60 } 61 } 62 63 /** 64 * 页é¢å¸è½½æ¶çå åºä¸æ¥æ¹æ³ 65 * ä¼å ä½¿ç¨ sendBeaconï¼ä¸é»å¡é¡µé¢å ³éï¼ï¼ä¸å¯ç¨æ¶é级为 fetch keepalive 66 * @param {string} url - ç®æ æ¥å£å°å 67 */ 68 function sendBeaconFallback(url) { 69 if (typeof navigator === 'undefined') return; 70 71 if (typeof navigator.sendBeacon === 'function') { 72 const blob = new Blob([cachedBody], { type: 'application/json' }); 73 navigator.sendBeacon(url, blob); 74 return; 75 } 76 77 // sendBeacon ä¸å¯ç¨æ¶é级为 fetch 78 postJSON(url); 79 } 80 81 // ==================== 䏿¥é»è¾ ==================== 82 83 /** 䏿¥è®¿é®äºä»¶ï¼ä» 馿¬¡è°ç¨çæï¼ */ 84 function reportVisit() { 85 if (hasVisitReported) return; 86 hasVisitReported = true; 87 postJSON(VISIT_API); 88 } 89 90 /** 䏿¥æ´»è·äºä»¶ï¼ä» 馿¬¡è°ç¨çæï¼ */ 91 function reportActive() { 92 if (hasActiveReported) return; 93 hasActiveReported = true; 94 postJSON(ACTIVE_API); 95 } 96 97 /** 98 * 页é¢ç¦»å¼æ¶çæ´»è·å åºä¸æ¥ 99 * ä» å¨æªä¸æ¥è¿æ´»è· ä¸ ç´¯è®¡åç ⥠ACTIVE_STAY_SECONDS æ¶è§¦å 100 */ 101 function reportActiveOnLeave() { 102 if (hasActiveReported) return; 103 104 const stayedMs = Date.now() - enterAt; 105 if (stayedMs >= ACTIVE_STAY_SECONDS * 1000) { 106 hasActiveReported = true; 107 sendBeaconFallback(ACTIVE_API); 108 } 109 } 110 111 // ==================== äºä»¶ç»å® ==================== 112 113 /** ç»å®æææ´»è·å¤å®ä¿¡å·å页é¢çå½å¨æçå¬å¨ */ 114 function bindActiveSignals() { 115 // 1. 交äºä¿¡å·ï¼ç¹å»ã馿¬¡æ»å¨ãè·¯ç±åå 116 document.addEventListener('click', reportActive, { passive: true }); 117 118 window.addEventListener( 119 'scroll', 120 () => { 121 if (scrollTriggered) return; 122 scrollTriggered = true; 123 reportActive(); 124 }, 125 { passive: true }, 126 ); 127 128 window.addEventListener('hashchange', reportActive, { passive: true }); 129 window.addEventListener('popstate', reportActive, { passive: true }); 130
131 // 2. åçæ¶é¿ä¿¡å·ï¼è¾¾å°éå¼èªå¨å¤å®ä¸ºæ´»è· 132 stayTimer = window.setTimeout(reportActive, ACTIVE_STAY_SECONDS * 1000); 133 134 // 3. 页é¢å¸è½½/éèä¿¡å·ï¼å åºä¸æ¥ 135 window.addEventListener('beforeunload', reportActiveOnLeave); 136 window.addEventListener('pagehide', reportActiveOnLeave); 137 138 document.addEventListener('visibilitychange', () => { 139 if (document.visibilityState === 'hidden') { 140 reportActiveOnLeave(); 141 } 142 }); 143 } 144 145 // ==================== åå§åå ¥å£ ==================== 146 147 function init() { 148 reportVisit(); 149 bindActiveSignals(); 150 } 151 152 // å ¼å®¹ DOM å°æªå°±ç»ªçæ åµ 153 if (document.readyState === 'loading') { 154 document.addEventListener('DOMContentLoaded', init); 155 } else { 156 init(); 157 } 158 159 // 页é¢éèæ¶æ¸ ç宿¶å¨ï¼é²æ¢åå°æ ç¾é¡µè¯¯è§¦å 160 window.addEventListener('pagehide', () => { 161 if (stayTimer) { 162 window.clearTimeout(stayTimer); 163 stayTimer = null; 164 } 165 }); 166})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.