1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
| // 使用 IIFE 避免全局污染 (function() { // 标记是否已经获取过 IP 信息(当前会话内只获取一次即可) let ipInfoLoaded = false; let cachedHTML = null;
const fetchIpInfo = async () => { const welcomeInfo = document.querySelector('#welcome-info'); if (!welcomeInfo) return; // 如果已经加载过,直接恢复缓存的内容 if (ipInfoLoaded && cachedHTML) { welcomeInfo.innerHTML = cachedHTML; return; } // 显示加载状态 welcomeInfo.innerHTML = '<div class="loading"><i class="fas fa-spinner fa-spin"></i> 定位中...</div>'; // 备用 API 列表(ipinfo.io 在国内可能被拦截,放在后面) const apis = [ { url: 'https://api.ip.sb/geoip', parser: (d) => ({ country: d.country, region: d.region, city: d.city, loc: d.latitude && d.longitude ? `${d.latitude},${d.longitude}` : null }) }, { url: 'https://ipapi.co/json/', parser: (d) => ({ country: d.country_code, region: d.region, city: d.city, loc: d.latitude && d.longitude ? `${d.latitude},${d.longitude}` : null }) }, { url: 'https://ipinfo.io/json', parser: (d) => ({ country: d.country, region: d.region, city: d.city, loc: d.loc }) } ]; let data = null; for (const api of apis) { try { const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), 3000); const res = await fetch(api.url, { signal: controller.signal, headers: { 'Accept': 'application/json' } }); clearTimeout(timeout); if (res.ok) { const raw = await res.json(); data = api.parser(raw); break; } } catch (e) { continue; } } // 渲染内容 if (data) { const { country, region, city, loc } = data; const [lat, lng] = loc ? loc.split(',').map(Number) : []; const myLat = 31.707754; const myLng = 119.825873; const dist = (lat && lng) ? calculateDistance(lng, lat, myLng, myLat) : null; const location = country === "CN" || country === "China" ? `${region || ''} ${city || ''}`.trim() : (country || '地球'); cachedHTML = ` <div class="welcome-content"> <p>欢迎来自 <span class="location">${location || '神秘星球'}</span> 的道友 💖</p> ${dist ? `<p>距博主约 <span class="distance">${dist}</span> 公里</p>` : ''} <p class="greeting">${getTimeGreeting()}</p> </div> `; ipInfoLoaded = true; welcomeInfo.innerHTML = cachedHTML; } else { cachedHTML = ` <div class="welcome-content"> <p>🎉 欢迎来到我的博客!</p> <p class="greeting">${getTimeGreeting()}</p> </div> `; ipInfoLoaded = true; welcomeInfo.innerHTML = cachedHTML; } };
const calculateDistance = (lng1, lat1, lng2, lat2) => { if (!lat1 || !lng1 || !lat2 || !lng2) return null; const R = 6371; const rad = Math.PI / 180; const dLat = (lat2 - lat1) * rad; const dLon = (lng2 - lng1) * rad; const a = Math.sin(dLat/2) ** 2 + Math.cos(lat1 * rad) * Math.cos(lat2 * rad) * Math.sin(dLon/2) ** 2; return Math.round(R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))); };
const getTimeGreeting = () => { const hour = new Date().getHours(); if (hour < 6) return "It's late, pay attention to rest 🌙"; if (hour < 12) return "Good morning, start your day. ☀️"; if (hour < 18) return "Good afternoon. Good work. ☕"; return "Good evening. May you have a good mood. 🌆"; };
// ===== 初始化策略 ===== // 1. 首次加载 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', fetchIpInfo); } else { fetchIpInfo(); }
// 2. 安知鱼主题 PJAX 事件(关键) // 安知鱼使用 pjax:complete,但 footer 不刷新,所以需要手动恢复内容 document.addEventListener('pjax:complete', () => { // PJAX 完成后,检查 welcome-info 是否存在 setTimeout(() => { const welcomeInfo = document.querySelector('#welcome-info'); if (welcomeInfo) { if (cachedHTML && ipInfoLoaded) { // 已经有缓存,直接恢复 welcomeInfo.innerHTML = cachedHTML; } else { // 首次或缓存丢失,重新获取 fetchIpInfo(); } } }, 100); // 延迟确保 DOM 已更新 });
// 3. 浏览器前进/后退按钮 window.addEventListener('popstate', () => { setTimeout(() => { const welcomeInfo = document.querySelector('#welcome-info'); if (welcomeInfo && cachedHTML && ipInfoLoaded) { welcomeInfo.innerHTML = cachedHTML; } }, 100); });
})();
|