perf(页面加载): 优化价格显示性能并添加加载状态处理
- 改用DOMContentLoaded事件提前初始化页面 - 实现渐进式价格显示:基础价格→加载中→实时价格 - 为fetchVisitData添加超时和重试机制 - 新增价格状态视觉区分样式 - 从2分钟等待优化为立即显示基础价格,后台异步更新
This commit is contained in:
180
script.js
180
script.js
@@ -187,17 +187,57 @@ function initAdPositions() {
|
||||
}
|
||||
|
||||
// 获取访问量数据
|
||||
async function fetchVisitData() {
|
||||
try {
|
||||
const response = await fetch('info.php');
|
||||
if (!response.ok) {
|
||||
throw new Error('获取访问量数据失败');
|
||||
/**
|
||||
* 获取访问量数据(带超时和重试机制)
|
||||
* @param {number} timeout 超时时间(毫秒)
|
||||
* @param {number} retries 重试次数
|
||||
* @returns {Promise<boolean>} 是否成功获取数据
|
||||
*/
|
||||
async function fetchVisitData(timeout = 10000, retries = 2) {
|
||||
for (let attempt = 0; attempt <= retries; attempt++) {
|
||||
try {
|
||||
console.log(`正在获取访问量数据... (尝试 ${attempt + 1}/${retries + 1})`);
|
||||
|
||||
// 创建带超时的fetch请求
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
||||
|
||||
const response = await fetch('info.php', {
|
||||
signal: controller.signal,
|
||||
cache: 'no-cache'
|
||||
});
|
||||
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// 验证数据完整性
|
||||
if (data && typeof data.last_month_pv === 'number') {
|
||||
visitData = data;
|
||||
console.log('访问量数据获取成功:', visitData);
|
||||
return true;
|
||||
} else {
|
||||
throw new Error('返回数据格式不正确');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.warn(`获取访问量数据失败 (尝试 ${attempt + 1}/${retries + 1}):`, error.message);
|
||||
|
||||
// 如果是最后一次尝试,记录错误但不抛出异常
|
||||
if (attempt === retries) {
|
||||
console.error('所有重试均失败,将使用基础价格');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 等待一段时间后重试
|
||||
await new Promise(resolve => setTimeout(resolve, 1000 * (attempt + 1)));
|
||||
}
|
||||
visitData = await response.json();
|
||||
console.log('访问量数据已更新:', visitData);
|
||||
} catch (error) {
|
||||
console.error('获取访问量数据时出错:', error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 根据访问量获取价格系数
|
||||
@@ -216,9 +256,63 @@ function calculateActualPrice(basePrice, monthlyPV) {
|
||||
return Math.round(basePrice * coefficient);
|
||||
}
|
||||
|
||||
// 更新所有广告位的价格显示
|
||||
/**
|
||||
* 显示基础价格(不依赖API数据)
|
||||
*/
|
||||
function showBasePrices() {
|
||||
console.log('显示基础价格...');
|
||||
Object.entries(AD_POSITIONS).forEach(([adId, adConfig]) => {
|
||||
const prices = adConfig.prices;
|
||||
|
||||
// 显示月付基础价格
|
||||
if (prices.monthly) {
|
||||
const monthlyElement = document.getElementById(`${adId}-monthly`);
|
||||
if (monthlyElement) {
|
||||
monthlyElement.textContent = prices.monthly.toLocaleString();
|
||||
monthlyElement.classList.add('base-price');
|
||||
}
|
||||
}
|
||||
|
||||
// 显示年付基础价格
|
||||
if (prices.yearly) {
|
||||
const yearlyElement = document.getElementById(`${adId}-yearly`);
|
||||
if (yearlyElement) {
|
||||
yearlyElement.textContent = prices.yearly.toLocaleString();
|
||||
yearlyElement.classList.add('base-price');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示价格加载状态
|
||||
*/
|
||||
function showPriceLoading() {
|
||||
console.log('显示价格加载状态...');
|
||||
Object.entries(AD_POSITIONS).forEach(([adId, adConfig]) => {
|
||||
const prices = adConfig.prices;
|
||||
|
||||
if (prices.monthly) {
|
||||
const monthlyElement = document.getElementById(`${adId}-monthly`);
|
||||
if (monthlyElement) {
|
||||
monthlyElement.innerHTML = '<span class="loading-price">计算中...</span>';
|
||||
}
|
||||
}
|
||||
|
||||
if (prices.yearly) {
|
||||
const yearlyElement = document.getElementById(`${adId}-yearly`);
|
||||
if (yearlyElement) {
|
||||
yearlyElement.innerHTML = '<span class="loading-price">计算中...</span>';
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新所有广告位的价格显示(实时价格)
|
||||
*/
|
||||
function updateAllAdPrices() {
|
||||
console.log('开始更新价格...');
|
||||
console.log('开始更新实时价格...');
|
||||
try {
|
||||
Object.entries(AD_POSITIONS).forEach(([adId, adConfig]) => {
|
||||
const prices = adConfig.prices;
|
||||
@@ -229,6 +323,8 @@ function updateAllAdPrices() {
|
||||
if (monthlyElement) {
|
||||
const actualPrice = calculateActualPrice(prices.monthly, visitData.last_month_pv);
|
||||
monthlyElement.textContent = actualPrice.toLocaleString();
|
||||
monthlyElement.classList.remove('base-price', 'loading-price');
|
||||
monthlyElement.classList.add('real-time-price');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,11 +334,16 @@ function updateAllAdPrices() {
|
||||
if (yearlyElement) {
|
||||
const actualPrice = calculateActualPrice(prices.yearly, visitData.last_month_pv);
|
||||
yearlyElement.textContent = actualPrice.toLocaleString();
|
||||
yearlyElement.classList.remove('base-price', 'loading-price');
|
||||
yearlyElement.classList.add('real-time-price');
|
||||
}
|
||||
}
|
||||
});
|
||||
console.log('实时价格更新完成');
|
||||
} catch (error) {
|
||||
console.error('更新价格时出错:', error);
|
||||
// 如果更新失败,回退到基础价格
|
||||
showBasePrices();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,15 +468,54 @@ document.querySelector('.contact-form').addEventListener('submit', function(e) {
|
||||
});
|
||||
|
||||
// 确保页面完全加载后再执行
|
||||
window.onload = async function() {
|
||||
console.log('页面加载完成,开始初始化...');
|
||||
initAdPositions();
|
||||
await fetchVisitData();
|
||||
updateAllAdPrices();
|
||||
/**
|
||||
* 页面初始化函数
|
||||
*/
|
||||
async function initializePage() {
|
||||
console.log('开始初始化页面...');
|
||||
|
||||
// 每5分钟更新一次访问量数据
|
||||
// 1. 立即初始化广告位和显示基础价格
|
||||
initAdPositions();
|
||||
showBasePrices();
|
||||
console.log('基础价格显示完成');
|
||||
|
||||
// 2. 显示加载状态并异步获取实时数据
|
||||
setTimeout(() => {
|
||||
showPriceLoading();
|
||||
|
||||
// 异步获取访问量数据并更新价格
|
||||
fetchVisitData(15000, 3).then(success => {
|
||||
if (success) {
|
||||
updateAllAdPrices();
|
||||
} else {
|
||||
// 如果获取失败,回退到基础价格
|
||||
console.log('API获取失败,显示基础价格');
|
||||
showBasePrices();
|
||||
}
|
||||
});
|
||||
}, 100); // 短暂延迟确保基础价格先显示
|
||||
|
||||
// 3. 设置定期更新(每5分钟)
|
||||
setInterval(async () => {
|
||||
await fetchVisitData();
|
||||
updateAllAdPrices();
|
||||
console.log('定期更新访问量数据...');
|
||||
const success = await fetchVisitData(10000, 1);
|
||||
if (success) {
|
||||
updateAllAdPrices();
|
||||
}
|
||||
}, 5 * 60 * 1000);
|
||||
};
|
||||
}
|
||||
|
||||
// 使用DOMContentLoaded而不是window.onload,提前初始化
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('DOM加载完成,开始初始化...');
|
||||
initializePage();
|
||||
});
|
||||
|
||||
// 保留window.onload作为备用(防止DOMContentLoaded未触发)
|
||||
window.addEventListener('load', function() {
|
||||
// 检查是否已经初始化过
|
||||
if (!document.querySelector('.ad-positions').hasChildNodes()) {
|
||||
console.log('备用初始化触发...');
|
||||
initializePage();
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user