mirror of
https://github.com/Silentely/eSIM-Tools.git
synced 2026-09-03 06:24:20 +08:00
- 新增 .babelrc 配置文件,使用 Babel 进行代码转换和压缩 - 添加 PERFORMANCE.md 文件,详细说明性能优化措施 - 在 README.md 中增加性能优化相关说明 - 更新 index.html,添加 Service Worker 注册和性能优化脚本
310 lines
8.1 KiB
JavaScript
310 lines
8.1 KiB
JavaScript
// 性能优化模块
|
|
class PerformanceOptimizer {
|
|
constructor() {
|
|
this.isOnline = navigator.onLine;
|
|
this.init();
|
|
}
|
|
|
|
init() {
|
|
this.registerServiceWorker();
|
|
this.setupNetworkListeners();
|
|
this.optimizeImages();
|
|
this.setupScrollOptimization();
|
|
this.setupIntersectionObserver();
|
|
this.setupTouchOptimization();
|
|
}
|
|
|
|
// 注册Service Worker
|
|
async registerServiceWorker() {
|
|
if ('serviceWorker' in navigator) {
|
|
try {
|
|
const registration = await navigator.serviceWorker.register('/sw.js');
|
|
console.log('Service Worker registered:', registration);
|
|
|
|
// 检查更新
|
|
registration.addEventListener('updatefound', () => {
|
|
const newWorker = registration.installing;
|
|
newWorker.addEventListener('statechange', () => {
|
|
if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
|
|
this.showUpdateNotification();
|
|
}
|
|
});
|
|
});
|
|
} catch (error) {
|
|
console.error('Service Worker registration failed:', error);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 显示更新通知
|
|
showUpdateNotification() {
|
|
const notification = document.createElement('div');
|
|
notification.className = 'update-notification fade-in';
|
|
notification.innerHTML = `
|
|
<div class="notification-content">
|
|
<i class="fas fa-download me-2"></i>
|
|
新版本可用,点击刷新页面
|
|
<button class="btn btn-sm btn-primary ms-2" onclick="location.reload()">
|
|
刷新
|
|
</button>
|
|
</div>
|
|
`;
|
|
|
|
document.body.appendChild(notification);
|
|
|
|
setTimeout(() => {
|
|
notification.remove();
|
|
}, 10000);
|
|
}
|
|
|
|
// 设置网络监听器
|
|
setupNetworkListeners() {
|
|
window.addEventListener('online', () => {
|
|
this.isOnline = true;
|
|
this.showNetworkStatus('网络已连接', 'success');
|
|
});
|
|
|
|
window.addEventListener('offline', () => {
|
|
this.isOnline = false;
|
|
this.showNetworkStatus('网络已断开,使用离线模式', 'warning');
|
|
});
|
|
}
|
|
|
|
// 显示网络状态
|
|
showNetworkStatus(message, type) {
|
|
const toast = document.createElement('div');
|
|
toast.className = `network-status ${type} fade-in`;
|
|
toast.textContent = message;
|
|
|
|
document.body.appendChild(toast);
|
|
|
|
setTimeout(() => {
|
|
toast.classList.add('fade-out');
|
|
setTimeout(() => toast.remove(), 300);
|
|
}, 3000);
|
|
}
|
|
|
|
// 图片优化
|
|
optimizeImages() {
|
|
const images = document.querySelectorAll('img[data-src]');
|
|
|
|
if ('IntersectionObserver' in window) {
|
|
const imageObserver = new IntersectionObserver((entries, observer) => {
|
|
entries.forEach(entry => {
|
|
if (entry.isIntersecting) {
|
|
const img = entry.target;
|
|
this.loadImage(img);
|
|
observer.unobserve(img);
|
|
}
|
|
});
|
|
});
|
|
|
|
images.forEach(img => imageObserver.observe(img));
|
|
} else {
|
|
// 降级处理
|
|
images.forEach(img => this.loadImage(img));
|
|
}
|
|
}
|
|
|
|
// 加载图片
|
|
loadImage(img) {
|
|
const src = img.dataset.src;
|
|
if (!src) return;
|
|
|
|
// 检查WebP支持
|
|
if (this.supportsWebP()) {
|
|
img.src = src.replace(/\.(jpg|jpeg|png)$/i, '.webp');
|
|
} else {
|
|
img.src = src;
|
|
}
|
|
|
|
img.classList.add('fade-in');
|
|
img.removeAttribute('data-src');
|
|
}
|
|
|
|
// 检查WebP支持
|
|
supportsWebP() {
|
|
const canvas = document.createElement('canvas');
|
|
canvas.width = 1;
|
|
canvas.height = 1;
|
|
return canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0;
|
|
}
|
|
|
|
// 滚动优化
|
|
setupScrollOptimization() {
|
|
let ticking = false;
|
|
|
|
const handleScroll = () => {
|
|
if (!ticking) {
|
|
requestAnimationFrame(() => {
|
|
this.updateScrollEffects();
|
|
ticking = false;
|
|
});
|
|
ticking = true;
|
|
}
|
|
};
|
|
|
|
window.addEventListener('scroll', handleScroll, { passive: true });
|
|
}
|
|
|
|
// 更新滚动效果
|
|
updateScrollEffects() {
|
|
const scrolled = window.pageYOffset;
|
|
const parallaxElements = document.querySelectorAll('[data-parallax]');
|
|
|
|
parallaxElements.forEach(element => {
|
|
const speed = element.dataset.parallax || 0.5;
|
|
const yPos = -(scrolled * speed);
|
|
element.style.transform = `translateY(${yPos}px)`;
|
|
});
|
|
}
|
|
|
|
// 设置交叉观察器
|
|
setupIntersectionObserver() {
|
|
if (!('IntersectionObserver' in window)) return;
|
|
|
|
const observer = new IntersectionObserver((entries) => {
|
|
entries.forEach(entry => {
|
|
if (entry.isIntersecting) {
|
|
entry.target.classList.add('animate-in');
|
|
}
|
|
});
|
|
}, {
|
|
threshold: 0.1,
|
|
rootMargin: '0px 0px -50px 0px'
|
|
});
|
|
|
|
document.querySelectorAll('[data-animate]').forEach(el => {
|
|
observer.observe(el);
|
|
});
|
|
}
|
|
|
|
// 触摸优化
|
|
setupTouchOptimization() {
|
|
// 防止双击缩放
|
|
let lastTouchEnd = 0;
|
|
document.addEventListener('touchend', (event) => {
|
|
const now = (new Date()).getTime();
|
|
if (now - lastTouchEnd <= 300) {
|
|
event.preventDefault();
|
|
}
|
|
lastTouchEnd = now;
|
|
}, false);
|
|
|
|
// 优化触摸反馈
|
|
document.addEventListener('touchstart', (e) => {
|
|
const target = e.target.closest('.btn, .card, .form-control');
|
|
if (target) {
|
|
target.classList.add('touch-active');
|
|
}
|
|
}, { passive: true });
|
|
|
|
document.addEventListener('touchend', (e) => {
|
|
const target = e.target.closest('.btn, .card, .form-control');
|
|
if (target) {
|
|
setTimeout(() => {
|
|
target.classList.remove('touch-active');
|
|
}, 150);
|
|
}
|
|
}, { passive: true });
|
|
}
|
|
|
|
// 显示加载状态
|
|
showLoading(message = '加载中...') {
|
|
const overlay = document.createElement('div');
|
|
overlay.className = 'loading-overlay';
|
|
overlay.innerHTML = `
|
|
<div class="loading-content">
|
|
<div class="loading-spinner"></div>
|
|
<p class="mt-3">${message}</p>
|
|
</div>
|
|
`;
|
|
|
|
document.body.appendChild(overlay);
|
|
|
|
// 强制重绘
|
|
overlay.offsetHeight;
|
|
overlay.classList.add('show');
|
|
|
|
return overlay;
|
|
}
|
|
|
|
// 隐藏加载状态
|
|
hideLoading(overlay) {
|
|
if (overlay) {
|
|
overlay.classList.remove('show');
|
|
setTimeout(() => {
|
|
if (overlay.parentNode) {
|
|
overlay.parentNode.removeChild(overlay);
|
|
}
|
|
}, 300);
|
|
}
|
|
}
|
|
|
|
// 防抖函数
|
|
debounce(func, wait) {
|
|
let timeout;
|
|
return function executedFunction(...args) {
|
|
const later = () => {
|
|
clearTimeout(timeout);
|
|
func(...args);
|
|
};
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(later, wait);
|
|
};
|
|
}
|
|
|
|
// 节流函数
|
|
throttle(func, limit) {
|
|
let inThrottle;
|
|
return function() {
|
|
const args = arguments;
|
|
const context = this;
|
|
if (!inThrottle) {
|
|
func.apply(context, args);
|
|
inThrottle = true;
|
|
setTimeout(() => inThrottle = false, limit);
|
|
}
|
|
};
|
|
}
|
|
|
|
// 预加载关键资源
|
|
preloadCriticalResources() {
|
|
const criticalResources = [
|
|
'/src/styles/design-system.css',
|
|
'/src/styles/animations.css'
|
|
];
|
|
|
|
criticalResources.forEach(resource => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'preload';
|
|
link.href = resource;
|
|
link.as = 'style';
|
|
document.head.appendChild(link);
|
|
});
|
|
}
|
|
|
|
// 性能监控
|
|
setupPerformanceMonitoring() {
|
|
if ('performance' in window) {
|
|
window.addEventListener('load', () => {
|
|
setTimeout(() => {
|
|
const perfData = performance.getEntriesByType('navigation')[0];
|
|
console.log('页面加载性能:', {
|
|
DNS查询: perfData.domainLookupEnd - perfData.domainLookupStart,
|
|
TCP连接: perfData.connectEnd - perfData.connectStart,
|
|
请求响应: perfData.responseEnd - perfData.requestStart,
|
|
DOM解析: perfData.domContentLoadedEventEnd - perfData.domContentLoadedEventStart,
|
|
页面完全加载: perfData.loadEventEnd - perfData.loadEventStart
|
|
});
|
|
}, 0);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
// 初始化性能优化
|
|
const performanceOptimizer = new PerformanceOptimizer();
|
|
|
|
// 导出供其他模块使用
|
|
window.PerformanceOptimizer = PerformanceOptimizer;
|