/** * 组件懒加载工具 */ import { defineAsyncComponent, Component } from 'vue'; import { LoadingOutlined } from '@ant-design/icons-vue'; import { h } from 'vue'; // 加载状态组件 const LoadingComponent = { setup() { return () => h( 'div', { style: { display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '200px', fontSize: '16px', color: '#999' } }, [h(LoadingOutlined, { style: { marginRight: '8px' } }), '加载中...'] ); } }; // 错误状态组件 const ErrorComponent = { props: ['error'], setup(props: { error: Error }) { return () => h( 'div', { style: { display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', minHeight: '200px', padding: '20px', color: '#ff4d4f', backgroundColor: '#fff2f0', border: '1px solid #ffccc7', borderRadius: '6px' } }, [ h( 'div', { style: { fontSize: '16px', marginBottom: '8px' } }, '组件加载失败' ), h( 'div', { style: { fontSize: '12px', color: '#999' } }, props.error.message ), h( 'button', { style: { marginTop: '12px', padding: '4px 12px', border: '1px solid #d9d9d9', borderRadius: '4px', backgroundColor: '#fff', cursor: 'pointer' }, onClick: () => window.location.reload() }, '重新加载' ) ] ); } }; // 懒加载配置选项 interface LazyLoadOptions { loading?: Component; error?: Component; delay?: number; timeout?: number; retries?: number; retryDelay?: number; } // 默认配置 const defaultOptions: LazyLoadOptions = { loading: LoadingComponent, error: ErrorComponent, delay: 200, timeout: 30000, retries: 3, retryDelay: 1000 }; /** * 创建懒加载组件 * @param loader 组件加载函数 * @param options 配置选项 */ export function createLazyComponent( loader: () => Promise, options: LazyLoadOptions = {} ) { const config = { ...defaultOptions, ...options }; return defineAsyncComponent({ loader: createRetryLoader(loader, config.retries!, config.retryDelay!), loadingComponent: config.loading, errorComponent: config.error, delay: config.delay, timeout: config.timeout }); } /** * 创建带重试机制的加载器 */ function createRetryLoader( loader: () => Promise, retries: number, retryDelay: number ) { return async () => { let lastError: Error; for (let i = 0; i <= retries; i++) { try { return await loader(); } catch (error) { lastError = error as Error; if (i < retries) { await new Promise((resolve) => setTimeout(resolve, retryDelay)); console.warn(`组件加载失败,正在重试 (${i + 1}/${retries}):`, error); } } } throw lastError!; }; } /** * 路由懒加载 */ export function lazyRoute( loader: () => Promise, options?: LazyLoadOptions ) { return createLazyComponent(loader, { ...options, loading: options?.loading || { setup() { return () => h( 'div', { style: { display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '60vh', fontSize: '16px', color: '#999' } }, [ h(LoadingOutlined, { style: { marginRight: '8px' } }), '页面加载中...' ] ); } } }); } /** * 模态框懒加载 */ export function lazyModal( loader: () => Promise, options?: LazyLoadOptions ) { return createLazyComponent(loader, { ...options, loading: options?.loading || { setup() { return () => h( 'div', { style: { display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '300px', fontSize: '14px', color: '#999' } }, [h(LoadingOutlined, { style: { marginRight: '8px' } }), '加载中...'] ); } } }); } /** * 图表懒加载 */ export function lazyChart( loader: () => Promise, options?: LazyLoadOptions ) { return createLazyComponent(loader, { ...options, loading: options?.loading || { setup() { return () => h( 'div', { style: { display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '400px', backgroundColor: '#fafafa', border: '1px dashed #d9d9d9', borderRadius: '6px', fontSize: '14px', color: '#999' } }, [ h(LoadingOutlined, { style: { marginRight: '8px' } }), '图表加载中...' ] ); } } }); } /** * 预加载组件 */ export class ComponentPreloader { private preloadedComponents = new Map>(); /** * 预加载组件 */ preload(key: string, loader: () => Promise) { if (!this.preloadedComponents.has(key)) { this.preloadedComponents.set(key, loader()); } return this.preloadedComponents.get(key)!; } /** * 获取预加载的组件 */ get(key: string) { return this.preloadedComponents.get(key); } /** * 清除预加载的组件 */ clear(key?: string) { if (key) { this.preloadedComponents.delete(key); } else { this.preloadedComponents.clear(); } } /** * 批量预加载 */ batchPreload(components: Record Promise>) { Object.entries(components).forEach(([key, loader]) => { this.preload(key, loader); }); } } // 全局预加载器实例 export const componentPreloader = new ComponentPreloader(); /** * 智能懒加载 - 根据网络状况调整策略 */ export function smartLazyComponent( loader: () => Promise, options: LazyLoadOptions = {} ) { // 检测网络状况 const connection = (navigator as any).connection; const isSlowNetwork = connection && (connection.effectiveType === 'slow-2g' || connection.effectiveType === '2g' || connection.saveData); // 根据网络状况调整配置 const smartOptions = { ...options, timeout: isSlowNetwork ? 60000 : options.timeout || 30000, retries: isSlowNetwork ? 5 : options.retries || 3, retryDelay: isSlowNetwork ? 2000 : options.retryDelay || 1000 }; return createLazyComponent(loader, smartOptions); } /** * 可见性懒加载 - 只有当组件进入视口时才加载 */ export function visibilityLazyComponent( loader: () => Promise, options: LazyLoadOptions = {} ) { return defineAsyncComponent({ loader: () => { return new Promise((resolve, reject) => { const observer = new IntersectionObserver((entries) => { if (entries[0].isIntersecting) { observer.disconnect(); loader().then(resolve).catch(reject); } }); // 创建一个占位元素来观察 const placeholder = document.createElement('div'); document.body.appendChild(placeholder); observer.observe(placeholder); // 清理函数 setTimeout(() => { observer.disconnect(); document.body.removeChild(placeholder); reject(new Error('Visibility timeout')); }, options.timeout || 30000); }); }, loadingComponent: options.loading || LoadingComponent, errorComponent: options.error || ErrorComponent, delay: options.delay || 200 }); }