本章概述

性能优化是现代 Web 开发中的关键环节,特别是在使用 Bootstrap 这样的 CSS 框架时。本章将深入探讨如何优化 Bootstrap 项目的性能,包括 CSS 优化、JavaScript 优化、资源加载优化、构建流程优化等方面,并提供实用的最佳实践指南。

学习目标

  • 掌握 Bootstrap 项目的性能分析方法
  • 学习 CSS 和 JavaScript 的优化技术
  • 了解资源加载和缓存策略
  • 掌握构建工具的性能优化配置
  • 学习移动端性能优化技巧
  • 了解可访问性和 SEO 优化

CSS 性能优化

1. 减少 CSS 文件大小

移除未使用的 CSS

// postcss.config.js
// 使用 PurgeCSS 移除未使用的样式

const purgecss = require('@fullhuman/postcss-purgecss');

module.exports = {
  plugins: [
    purgecss({
      content: [
        './src/**/*.html',
        './src/**/*.js',
        './src/**/*.jsx',
        './src/**/*.ts',
        './src/**/*.tsx',
        './src/**/*.vue'
      ],
      // 保护 Bootstrap 的动态类名
      safelist: [
        /^btn-/,
        /^alert-/,
        /^badge-/,
        /^bg-/,
        /^text-/,
        /^border-/,
        /^rounded-/,
        /^shadow-/,
        /^p[xy]?-/,
        /^m[xy]?-/,
        /^w-/,
        /^h-/,
        /^d-/,
        /^flex-/,
        /^justify-/,
        /^align-/,
        /^position-/,
        /^top-/,
        /^bottom-/,
        /^start-/,
        /^end-/,
        /^translate-/,
        /^rotate-/,
        /^scale-/,
        /^opacity-/,
        /^overflow-/,
        /^user-/,
        /^pointer-/,
        /^cursor-/,
        /^z-/,
        /^col-/,
        /^row-/,
        /^g-/,
        /^gx-/,
        /^gy-/,
        /^offset-/,
        /^order-/,
        // 动态生成的类名
        /^carousel-/,
        /^modal-/,
        /^dropdown-/,
        /^nav-/,
        /^navbar-/,
        /^accordion-/,
        /^toast-/,
        /^tooltip-/,
        /^popover-/,
        /^offcanvas-/,
        // 状态类
        'show',
        'hide',
        'active',
        'disabled',
        'fade',
        'collapse',
        'collapsing',
        'was-validated',
        'is-valid',
        'is-invalid'
      ],
      // 默认提取器
      defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || [],
      // 自定义提取器
      extractors: [
        {
          extractor: content => {
            // 提取 JavaScript 中的类名
            const jsClasses = content.match(/["'`]([\w\s-]+)["'`]/g) || [];
            return jsClasses.map(match => match.slice(1, -1).split(' ')).flat();
          },
          extensions: ['js', 'jsx', 'ts', 'tsx']
        },
        {
          extractor: content => {
            // 提取 Vue 模板中的类名
            const vueClasses = content.match(/:?class="([^"]*)"/g) || [];
            return vueClasses.map(match => {
              const classStr = match.match(/"([^"]*)"/)[1];
              return classStr.split(' ');
            }).flat();
          },
          extensions: ['vue']
        }
      ]
    })
  ]
};

自定义 Bootstrap 构建

// custom-bootstrap.scss
// 只导入需要的 Bootstrap 组件

// 1. 导入必需的文件
@import "~bootstrap/scss/functions";
@import "~bootstrap/scss/variables";
@import "~bootstrap/scss/mixins";

// 2. 自定义变量(可选)
$primary: #007bff;
$secondary: #6c757d;
$enable-rounded: true;
$enable-shadows: false;
$enable-gradients: false;
$enable-transitions: true;
$enable-reduced-motion: true;
$enable-grid-classes: true;
$enable-container-classes: true;

// 3. 导入布局和可重用组件
@import "~bootstrap/scss/root";
@import "~bootstrap/scss/reboot";
@import "~bootstrap/scss/type";
@import "~bootstrap/scss/images";
@import "~bootstrap/scss/containers";
@import "~bootstrap/scss/grid";

// 4. 导入需要的组件(按需选择)
@import "~bootstrap/scss/tables";
@import "~bootstrap/scss/forms";
@import "~bootstrap/scss/buttons";
@import "~bootstrap/scss/transitions";
@import "~bootstrap/scss/dropdown";
@import "~bootstrap/scss/button-group";
@import "~bootstrap/scss/nav";
@import "~bootstrap/scss/navbar";
@import "~bootstrap/scss/card";
@import "~bootstrap/scss/accordion";
@import "~bootstrap/scss/breadcrumb";
@import "~bootstrap/scss/pagination";
@import "~bootstrap/scss/badge";
@import "~bootstrap/scss/alert";
@import "~bootstrap/scss/progress";
@import "~bootstrap/scss/list-group";
@import "~bootstrap/scss/close";
@import "~bootstrap/scss/toasts";
@import "~bootstrap/scss/modal";
@import "~bootstrap/scss/tooltip";
@import "~bootstrap/scss/popover";
@import "~bootstrap/scss/carousel";
@import "~bootstrap/scss/spinners";
@import "~bootstrap/scss/offcanvas";
@import "~bootstrap/scss/placeholders";

// 5. 导入工具类(可选择性导入)
@import "~bootstrap/scss/utilities";

// 6. 导入打印样式(可选)
// @import "~bootstrap/scss/print";

2. CSS 压缩和优化

// webpack.config.js
// Webpack CSS 优化配置

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');

module.exports = {
  mode: 'production',
  
  module: {
    rules: [
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              importLoaders: 2,
              sourceMap: false
            }
          },
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  ['autoprefixer'],
                  ['cssnano', {
                    preset: ['default', {
                      discardComments: {
                        removeAll: true
                      },
                      normalizeWhitespace: true,
                      colormin: true,
                      convertValues: true,
                      discardDuplicates: true,
                      discardEmpty: true,
                      mergeIdents: true,
                      mergeLonghand: true,
                      mergeRules: true,
                      minifyFontValues: true,
                      minifyGradients: true,
                      minifyParams: true,
                      minifySelectors: true,
                      normalizeCharset: true,
                      normalizeDisplayValues: true,
                      normalizePositions: true,
                      normalizeRepeatStyle: true,
                      normalizeString: true,
                      normalizeTimingFunctions: true,
                      normalizeUnicode: true,
                      normalizeUrl: true,
                      orderedValues: true,
                      reduceIdents: true,
                      reduceInitial: true,
                      reduceTransforms: true,
                      svgo: true,
                      uniqueSelectors: true
                    }]
                  }]
                ]
              }
            }
          },
          {
            loader: 'sass-loader',
            options: {
              implementation: require('sass'),
              sourceMap: false,
              sassOptions: {
                outputStyle: 'compressed'
              }
            }
          }
        ]
      }
    ]
  },
  
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash:8].css',
      chunkFilename: 'css/[name].[contenthash:8].chunk.css'
    })
  ],
  
  optimization: {
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          compress: {
            drop_console: true,
            drop_debugger: true
          }
        }
      }),
      new CssMinimizerPlugin({
        minimizerOptions: {
          preset: [
            'default',
            {
              discardComments: { removeAll: true }
            }
          ]
        }
      })
    ],
    
    splitChunks: {
      cacheGroups: {
        styles: {
          name: 'styles',
          type: 'css/mini-extract',
          chunks: 'all',
          enforce: true
        }
      }
    }
  }
};

3. 关键 CSS 内联

// critical-css.js
// 提取和内联关键 CSS

const critical = require('critical');
const path = require('path');

// 生成关键 CSS
critical.generate({
  // 基础配置
  base: 'dist/',
  src: 'index.html',
  dest: 'index-critical.html',
  
  // 视口尺寸
  dimensions: [
    {
      width: 320,
      height: 480
    },
    {
      width: 768,
      height: 1024
    },
    {
      width: 1200,
      height: 900
    }
  ],
  
  // 内联选项
  inline: true,
  minify: true,
  extract: true,
  
  // 忽略的规则
  ignore: {
    atrule: ['@font-face'],
    rule: [/\.sr-only/],
    decl: (node, value) => {
      // 忽略某些属性
      return /url\(/.test(value);
    }
  },
  
  // 包含的选择器
  include: [
    // Bootstrap 核心样式
    /\.container/,
    /\.row/,
    /\.col/,
    /\.btn/,
    /\.nav/,
    /\.navbar/,
    /\.card/,
    /\.alert/,
    // 自定义关键样式
    /\.hero/,
    /\.header/,
    /\.main-content/
  ],
  
  // 用户代理
  userAgent: 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)'
}, (err, output) => {
  if (err) {
    console.error('Critical CSS generation failed:', err);
  } else {
    console.log('Critical CSS generated successfully');
    console.log('Critical CSS size:', output.css.length, 'bytes');
  }
});

JavaScript 性能优化

1. 按需加载 Bootstrap JavaScript

// bootstrap-loader.js
// 动态加载 Bootstrap 组件

class BootstrapLoader {
  constructor() {
    this.loadedComponents = new Set();
    this.loadingPromises = new Map();
  }
  
  // 动态加载组件
  async loadComponent(componentName) {
    if (this.loadedComponents.has(componentName)) {
      return Promise.resolve();
    }
    
    if (this.loadingPromises.has(componentName)) {
      return this.loadingPromises.get(componentName);
    }
    
    const loadPromise = this._loadComponentModule(componentName);
    this.loadingPromises.set(componentName, loadPromise);
    
    try {
      await loadPromise;
      this.loadedComponents.add(componentName);
      this.loadingPromises.delete(componentName);
    } catch (error) {
      this.loadingPromises.delete(componentName);
      throw error;
    }
    
    return loadPromise;
  }
  
  // 加载组件模块
  async _loadComponentModule(componentName) {
    switch (componentName) {
      case 'modal':
        const { Modal } = await import('bootstrap/js/dist/modal');
        window.bootstrap = window.bootstrap || {};
        window.bootstrap.Modal = Modal;
        break;
        
      case 'dropdown':
        const { Dropdown } = await import('bootstrap/js/dist/dropdown');
        window.bootstrap = window.bootstrap || {};
        window.bootstrap.Dropdown = Dropdown;
        break;
        
      case 'carousel':
        const { Carousel } = await import('bootstrap/js/dist/carousel');
        window.bootstrap = window.bootstrap || {};
        window.bootstrap.Carousel = Carousel;
        break;
        
      case 'collapse':
        const { Collapse } = await import('bootstrap/js/dist/collapse');
        window.bootstrap = window.bootstrap || {};
        window.bootstrap.Collapse = Collapse;
        break;
        
      case 'tooltip':
        const { Tooltip } = await import('bootstrap/js/dist/tooltip');
        window.bootstrap = window.bootstrap || {};
        window.bootstrap.Tooltip = Tooltip;
        break;
        
      case 'popover':
        const { Popover } = await import('bootstrap/js/dist/popover');
        window.bootstrap = window.bootstrap || {};
        window.bootstrap.Popover = Popover;
        break;
        
      case 'toast':
        const { Toast } = await import('bootstrap/js/dist/toast');
        window.bootstrap = window.bootstrap || {};
        window.bootstrap.Toast = Toast;
        break;
        
      case 'alert':
        const { Alert } = await import('bootstrap/js/dist/alert');
        window.bootstrap = window.bootstrap || {};
        window.bootstrap.Alert = Alert;
        break;
        
      case 'button':
        const { Button } = await import('bootstrap/js/dist/button');
        window.bootstrap = window.bootstrap || {};
        window.bootstrap.Button = Button;
        break;
        
      case 'offcanvas':
        const { Offcanvas } = await import('bootstrap/js/dist/offcanvas');
        window.bootstrap = window.bootstrap || {};
        window.bootstrap.Offcanvas = Offcanvas;
        break;
        
      case 'scrollspy':
        const { ScrollSpy } = await import('bootstrap/js/dist/scrollspy');
        window.bootstrap = window.bootstrap || {};
        window.bootstrap.ScrollSpy = ScrollSpy;
        break;
        
      case 'tab':
        const { Tab } = await import('bootstrap/js/dist/tab');
        window.bootstrap = window.bootstrap || {};
        window.bootstrap.Tab = Tab;
        break;
        
      default:
        throw new Error(`Unknown Bootstrap component: ${componentName}`);
    }
  }
  
  // 批量加载组件
  async loadComponents(componentNames) {
    const loadPromises = componentNames.map(name => this.loadComponent(name));
    return Promise.all(loadPromises);
  }
  
  // 预加载组件
  preloadComponent(componentName) {
    // 使用 requestIdleCallback 在空闲时预加载
    if ('requestIdleCallback' in window) {
      requestIdleCallback(() => {
        this.loadComponent(componentName).catch(console.error);
      });
    } else {
      setTimeout(() => {
        this.loadComponent(componentName).catch(console.error);
      }, 100);
    }
  }
  
  // 自动检测并加载页面中的组件
  autoLoadComponents() {
    const componentSelectors = {
      modal: '[data-bs-toggle="modal"]',
      dropdown: '[data-bs-toggle="dropdown"]',
      carousel: '.carousel',
      collapse: '[data-bs-toggle="collapse"]',
      tooltip: '[data-bs-toggle="tooltip"]',
      popover: '[data-bs-toggle="popover"]',
      toast: '.toast',
      alert: '.alert-dismissible',
      offcanvas: '[data-bs-toggle="offcanvas"]',
      scrollspy: '[data-bs-spy="scroll"]',
      tab: '[data-bs-toggle="tab"], [data-bs-toggle="pill"]'
    };
    
    const componentsToLoad = [];
    
    Object.entries(componentSelectors).forEach(([component, selector]) => {
      if (document.querySelector(selector)) {
        componentsToLoad.push(component);
      }
    });
    
    if (componentsToLoad.length > 0) {
      return this.loadComponents(componentsToLoad);
    }
    
    return Promise.resolve();
  }
}

// 创建全局实例
const bootstrapLoader = new BootstrapLoader();

// 导出
export default bootstrapLoader;

// 使用示例
// import bootstrapLoader from './bootstrap-loader';
// 
// // 自动加载页面中的组件
// document.addEventListener('DOMContentLoaded', () => {
//   bootstrapLoader.autoLoadComponents();
// });
// 
// // 手动加载特定组件
// bootstrapLoader.loadComponent('modal').then(() => {
//   const modal = new bootstrap.Modal(document.getElementById('myModal'));
//   modal.show();
// });

2. JavaScript 代码分割和懒加载

// lazy-components.js
// 懒加载组件管理器

class LazyComponentManager {
  constructor() {
    this.observers = new Map();
    this.loadedComponents = new Set();
    this.componentRegistry = new Map();
    
    // 注册组件加载器
    this.registerComponents();
  }
  
  // 注册组件
  registerComponents() {
    // 模态框组件
    this.componentRegistry.set('modal', {
      selector: '[data-lazy-modal]',
      loader: () => import('./components/modal-component'),
      dependencies: ['modal']
    });
    
    // 轮播图组件
    this.componentRegistry.set('carousel', {
      selector: '[data-lazy-carousel]',
      loader: () => import('./components/carousel-component'),
      dependencies: ['carousel']
    });
    
    // 图表组件
    this.componentRegistry.set('chart', {
      selector: '[data-lazy-chart]',
      loader: () => import('./components/chart-component'),
      dependencies: []
    });
    
    // 数据表格组件
    this.componentRegistry.set('datatable', {
      selector: '[data-lazy-datatable]',
      loader: () => import('./components/datatable-component'),
      dependencies: []
    });
    
    // 地图组件
    this.componentRegistry.set('map', {
      selector: '[data-lazy-map]',
      loader: () => import('./components/map-component'),
      dependencies: []
    });
  }
  
  // 初始化懒加载
  init() {
    if (!('IntersectionObserver' in window)) {
      // 降级处理:直接加载所有组件
      this.loadAllComponents();
      return;
    }
    
    this.componentRegistry.forEach((config, componentName) => {
      this.observeComponent(componentName, config);
    });
  }
  
  // 观察组件
  observeComponent(componentName, config) {
    const elements = document.querySelectorAll(config.selector);
    
    if (elements.length === 0) return;
    
    const observer = new IntersectionObserver(
      (entries) => {
        entries.forEach(entry => {
          if (entry.isIntersecting) {
            this.loadComponent(componentName, entry.target);
            observer.unobserve(entry.target);
          }
        });
      },
      {
        rootMargin: '50px 0px',
        threshold: 0.1
      }
    );
    
    elements.forEach(element => {
      observer.observe(element);
    });
    
    this.observers.set(componentName, observer);
  }
  
  // 加载组件
  async loadComponent(componentName, element) {
    if (this.loadedComponents.has(componentName)) {
      return;
    }
    
    const config = this.componentRegistry.get(componentName);
    if (!config) {
      console.warn(`Component ${componentName} not found`);
      return;
    }
    
    try {
      // 显示加载状态
      this.showLoadingState(element);
      
      // 加载 Bootstrap 依赖
      if (config.dependencies.length > 0) {
        await bootstrapLoader.loadComponents(config.dependencies);
      }
      
      // 加载组件模块
      const module = await config.loader();
      const ComponentClass = module.default || module[componentName];
      
      // 初始化组件
      if (ComponentClass) {
        new ComponentClass(element);
      }
      
      this.loadedComponents.add(componentName);
      this.hideLoadingState(element);
      
      // 触发加载完成事件
      element.dispatchEvent(new CustomEvent('component:loaded', {
        detail: { componentName }
      }));
      
    } catch (error) {
      console.error(`Failed to load component ${componentName}:`, error);
      this.showErrorState(element, error);
    }
  }
  
  // 显示加载状态
  showLoadingState(element) {
    const loader = document.createElement('div');
    loader.className = 'component-loader d-flex justify-content-center align-items-center';
    loader.innerHTML = `
      <div class="spinner-border text-primary" role="status">
        <span class="visually-hidden">Loading...</span>
      </div>
    `;
    loader.style.cssText = `
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background: rgba(255, 255, 255, 0.8);
      z-index: 1000;
    `;
    
    element.style.position = 'relative';
    element.appendChild(loader);
  }
  
  // 隐藏加载状态
  hideLoadingState(element) {
    const loader = element.querySelector('.component-loader');
    if (loader) {
      loader.remove();
    }
  }
  
  // 显示错误状态
  showErrorState(element, error) {
    const errorDiv = document.createElement('div');
    errorDiv.className = 'alert alert-danger';
    errorDiv.innerHTML = `
      <h6>组件加载失败</h6>
      <p class="mb-0">请刷新页面重试</p>
    `;
    
    this.hideLoadingState(element);
    element.appendChild(errorDiv);
  }
  
  // 加载所有组件(降级处理)
  async loadAllComponents() {
    const loadPromises = [];
    
    this.componentRegistry.forEach((config, componentName) => {
      const elements = document.querySelectorAll(config.selector);
      elements.forEach(element => {
        loadPromises.push(this.loadComponent(componentName, element));
      });
    });
    
    await Promise.allSettled(loadPromises);
  }
  
  // 预加载组件
  preloadComponent(componentName) {
    const config = this.componentRegistry.get(componentName);
    if (!config) return;
    
    // 使用 link preload 预加载模块
    const link = document.createElement('link');
    link.rel = 'modulepreload';
    link.href = config.loader.toString().match(/import\('([^']+)'\)/)?.[1];
    if (link.href) {
      document.head.appendChild(link);
    }
  }
  
  // 销毁观察器
  destroy() {
    this.observers.forEach(observer => {
      observer.disconnect();
    });
    this.observers.clear();
  }
}

// 创建全局实例
const lazyComponentManager = new LazyComponentManager();

// 导出
export default lazyComponentManager;

3. 事件委托优化

// event-delegation.js
// 高性能事件委托管理器

class EventDelegationManager {
  constructor() {
    this.delegatedEvents = new Map();
    this.eventHandlers = new Map();
    this.throttledEvents = new Set(['scroll', 'resize', 'mousemove']);
    this.debouncedEvents = new Set(['input', 'keyup']);
    
    this.init();
  }
  
  init() {
    // 设置全局事件委托
    this.setupGlobalDelegation();
    
    // 优化滚动和调整大小事件
    this.optimizePerformanceEvents();
  }
  
  // 设置全局事件委托
  setupGlobalDelegation() {
    // Bootstrap 组件事件委托
    this.delegate('click', '[data-bs-toggle]', this.handleBootstrapToggle.bind(this));
    this.delegate('click', '[data-bs-dismiss]', this.handleBootstrapDismiss.bind(this));
    this.delegate('click', '.btn', this.handleButtonClick.bind(this));
    this.delegate('submit', 'form', this.handleFormSubmit.bind(this));
    
    // 自定义组件事件委托
    this.delegate('click', '[data-action]', this.handleDataAction.bind(this));
    this.delegate('change', '[data-filter]', this.handleDataFilter.bind(this));
    this.delegate('input', '[data-search]', this.handleDataSearch.bind(this));
  }
  
  // 事件委托
  delegate(eventType, selector, handler, options = {}) {
    const eventKey = `${eventType}:${selector}`;
    
    if (this.delegatedEvents.has(eventKey)) {
      return; // 避免重复绑定
    }
    
    let wrappedHandler = handler;
    
    // 应用节流或防抖
    if (this.throttledEvents.has(eventType)) {
      wrappedHandler = this.throttle(handler, options.throttleDelay || 16);
    } else if (this.debouncedEvents.has(eventType)) {
      wrappedHandler = this.debounce(handler, options.debounceDelay || 300);
    }
    
    const delegatedHandler = (event) => {
      const target = event.target.closest(selector);
      if (target) {
        wrappedHandler.call(target, event, target);
      }
    };
    
    document.addEventListener(eventType, delegatedHandler, {
      passive: options.passive !== false,
      capture: options.capture || false
    });
    
    this.delegatedEvents.set(eventKey, delegatedHandler);
    this.eventHandlers.set(eventKey, handler);
  }
  
  // 处理 Bootstrap toggle 事件
  handleBootstrapToggle(event, element) {
    const toggle = element.getAttribute('data-bs-toggle');
    const target = element.getAttribute('data-bs-target') || element.getAttribute('href');
    
    // 确保组件已加载
    bootstrapLoader.loadComponent(toggle).then(() => {
      // 让 Bootstrap 处理默认行为
    }).catch(console.error);
  }
  
  // 处理 Bootstrap dismiss 事件
  handleBootstrapDismiss(event, element) {
    const dismiss = element.getAttribute('data-bs-dismiss');
    
    // 确保组件已加载
    bootstrapLoader.loadComponent(dismiss).then(() => {
      // 让 Bootstrap 处理默认行为
    }).catch(console.error);
  }
  
  // 处理按钮点击
  handleButtonClick(event, element) {
    // 防止重复点击
    if (element.disabled || element.classList.contains('disabled')) {
      event.preventDefault();
      return;
    }
    
    // 添加点击反馈
    this.addClickFeedback(element);
  }
  
  // 处理表单提交
  handleFormSubmit(event, element) {
    // 表单验证
    if (!element.checkValidity()) {
      event.preventDefault();
      element.classList.add('was-validated');
      return;
    }
    
    // 防止重复提交
    const submitBtn = element.querySelector('[type="submit"]');
    if (submitBtn) {
      submitBtn.disabled = true;
      setTimeout(() => {
        submitBtn.disabled = false;
      }, 2000);
    }
  }
  
  // 处理数据操作
  handleDataAction(event, element) {
    const action = element.getAttribute('data-action');
    const target = element.getAttribute('data-target');
    
    switch (action) {
      case 'toggle-class':
        const className = element.getAttribute('data-class');
        const targetElement = document.querySelector(target);
        if (targetElement && className) {
          targetElement.classList.toggle(className);
        }
        break;
        
      case 'copy-text':
        const text = element.getAttribute('data-text') || element.textContent;
        this.copyToClipboard(text);
        break;
        
      case 'scroll-to':
        const scrollTarget = document.querySelector(target);
        if (scrollTarget) {
          scrollTarget.scrollIntoView({ behavior: 'smooth' });
        }
        break;
    }
  }
  
  // 处理数据过滤
  handleDataFilter(event, element) {
    const filterValue = element.value;
    const filterTarget = element.getAttribute('data-filter');
    const items = document.querySelectorAll(`[data-filter-item="${filterTarget}"]`);
    
    items.forEach(item => {
      const itemValue = item.getAttribute('data-filter-value');
      const shouldShow = !filterValue || itemValue.includes(filterValue);
      item.style.display = shouldShow ? '' : 'none';
    });
  }
  
  // 处理数据搜索
  handleDataSearch(event, element) {
    const searchValue = element.value.toLowerCase();
    const searchTarget = element.getAttribute('data-search');
    const items = document.querySelectorAll(`[data-search-item="${searchTarget}"]`);
    
    items.forEach(item => {
      const itemText = item.textContent.toLowerCase();
      const shouldShow = !searchValue || itemText.includes(searchValue);
      item.style.display = shouldShow ? '' : 'none';
    });
  }
  
  // 添加点击反馈
  addClickFeedback(element) {
    element.style.transform = 'scale(0.98)';
    element.style.transition = 'transform 0.1s ease';
    
    setTimeout(() => {
      element.style.transform = '';
      setTimeout(() => {
        element.style.transition = '';
      }, 100);
    }, 100);
  }
  
  // 复制到剪贴板
  async copyToClipboard(text) {
    try {
      await navigator.clipboard.writeText(text);
      this.showToast('已复制到剪贴板', 'success');
    } catch (error) {
      console.error('复制失败:', error);
      this.showToast('复制失败', 'error');
    }
  }
  
  // 显示提示
  showToast(message, type = 'info') {
    // 简单的提示实现
    const toast = document.createElement('div');
    toast.className = `alert alert-${type === 'error' ? 'danger' : type} position-fixed`;
    toast.style.cssText = `
      top: 20px;
      right: 20px;
      z-index: 9999;
      min-width: 200px;
    `;
    toast.textContent = message;
    
    document.body.appendChild(toast);
    
    setTimeout(() => {
      toast.remove();
    }, 3000);
  }
  
  // 优化性能事件
  optimizePerformanceEvents() {
    // 优化滚动事件
    let scrollTimer;
    const optimizedScrollHandler = this.throttle(() => {
      document.body.classList.add('is-scrolling');
      
      clearTimeout(scrollTimer);
      scrollTimer = setTimeout(() => {
        document.body.classList.remove('is-scrolling');
      }, 150);
    }, 16);
    
    window.addEventListener('scroll', optimizedScrollHandler, { passive: true });
    
    // 优化调整大小事件
    const optimizedResizeHandler = this.debounce(() => {
      // 触发自定义调整大小事件
      window.dispatchEvent(new CustomEvent('optimized:resize'));
    }, 250);
    
    window.addEventListener('resize', optimizedResizeHandler, { passive: true });
  }
  
  // 节流函数
  throttle(func, delay) {
    let timeoutId;
    let lastExecTime = 0;
    
    return function (...args) {
      const currentTime = Date.now();
      
      if (currentTime - lastExecTime > delay) {
        func.apply(this, args);
        lastExecTime = currentTime;
      } else {
        clearTimeout(timeoutId);
        timeoutId = setTimeout(() => {
          func.apply(this, args);
          lastExecTime = Date.now();
        }, delay - (currentTime - lastExecTime));
      }
    };
  }
  
  // 防抖函数
  debounce(func, delay) {
    let timeoutId;
    
    return function (...args) {
      clearTimeout(timeoutId);
      timeoutId = setTimeout(() => {
        func.apply(this, args);
      }, delay);
    };
  }
  
  // 移除事件委托
  undelegate(eventType, selector) {
    const eventKey = `${eventType}:${selector}`;
    const handler = this.delegatedEvents.get(eventKey);
    
    if (handler) {
      document.removeEventListener(eventType, handler);
      this.delegatedEvents.delete(eventKey);
      this.eventHandlers.delete(eventKey);
    }
  }
  
  // 销毁所有事件
  destroy() {
    this.delegatedEvents.forEach((handler, eventKey) => {
      const [eventType] = eventKey.split(':');
      document.removeEventListener(eventType, handler);
    });
    
    this.delegatedEvents.clear();
    this.eventHandlers.clear();
  }
}

// 创建全局实例
const eventDelegationManager = new EventDelegationManager();

// 导出
export default eventDelegationManager;

资源加载优化

1. 资源预加载策略

<!-- resource-preload.html -->
<!-- 资源预加载示例 -->

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Bootstrap 性能优化示例</title>
  
  <!-- DNS 预解析 -->
  <link rel="dns-prefetch" href="//fonts.googleapis.com">
  <link rel="dns-prefetch" href="//cdn.jsdelivr.net">
  <link rel="dns-prefetch" href="//api.example.com">
  
  <!-- 预连接重要资源 -->
  <link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  
  <!-- 预加载关键资源 -->
  <link rel="preload" href="/css/bootstrap.min.css" as="style">
  <link rel="preload" href="/css/custom.css" as="style">
  <link rel="preload" href="/js/bootstrap.bundle.min.js" as="script">
  <link rel="preload" href="/fonts/custom-font.woff2" as="font" type="font/woff2" crossorigin>
  
  <!-- 预加载关键图片 -->
  <link rel="preload" href="/images/hero-bg.webp" as="image">
  <link rel="preload" href="/images/logo.svg" as="image">
  
  <!-- 模块预加载 -->
  <link rel="modulepreload" href="/js/modules/app.js">
  <link rel="modulepreload" href="/js/modules/components.js">
  
  <!-- 关键 CSS 内联 -->
  <style>
    /* 关键 CSS 样式 */
    .hero {
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      min-height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    .loading-skeleton {
      background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
      background-size: 200% 100%;
      animation: loading 1.5s infinite;
    }
    
    @keyframes loading {
      0% { background-position: 200% 0; }
      100% { background-position: -200% 0; }
    }
  </style>
  
  <!-- 非关键 CSS 异步加载 -->
  <link rel="preload" href="/css/bootstrap.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
  <noscript><link rel="stylesheet" href="/css/bootstrap.min.css"></noscript>
  
  <link rel="preload" href="/css/custom.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
  <noscript><link rel="stylesheet" href="/css/custom.css"></noscript>
</head>
<body>
  <!-- 页面内容 -->
  <div class="hero">
    <div class="container text-center text-white">
      <h1 class="display-4 mb-4">Bootstrap 性能优化</h1>
      <p class="lead mb-4">高性能的 Web 应用开发实践</p>
      <button class="btn btn-primary btn-lg" data-lazy-modal data-bs-target="#exampleModal">
        打开模态框
      </button>
    </div>
  </div>
  
  <!-- 懒加载内容区域 -->
  <div class="container my-5">
    <div class="row">
      <div class="col-md-6 mb-4">
        <div class="card" data-lazy-chart>
          <div class="card-header">
            <h5>销售图表</h5>
          </div>
          <div class="card-body">
            <div class="loading-skeleton" style="height: 300px;"></div>
          </div>
        </div>
      </div>
      
      <div class="col-md-6 mb-4">
        <div class="card" data-lazy-datatable>
          <div class="card-header">
            <h5>数据表格</h5>
          </div>
          <div class="card-body">
            <div class="loading-skeleton" style="height: 300px;"></div>
          </div>
        </div>
      </div>
    </div>
  </div>
  
  <!-- 资源加载脚本 -->
  <script>
    // 资源加载管理器
    class ResourceLoader {
      constructor() {
        this.loadedResources = new Set();
        this.loadingPromises = new Map();
      }
      
      // 异步加载 CSS
      loadCSS(href, media = 'all') {
        if (this.loadedResources.has(href)) {
          return Promise.resolve();
        }
        
        if (this.loadingPromises.has(href)) {
          return this.loadingPromises.get(href);
        }
        
        const promise = new Promise((resolve, reject) => {
          const link = document.createElement('link');
          link.rel = 'stylesheet';
          link.href = href;
          link.media = media;
          
          link.onload = () => {
            this.loadedResources.add(href);
            resolve();
          };
          
          link.onerror = () => {
            reject(new Error(`Failed to load CSS: ${href}`));
          };
          
          document.head.appendChild(link);
        });
        
        this.loadingPromises.set(href, promise);
        return promise;
      }
      
      // 异步加载 JavaScript
      loadJS(src, type = 'text/javascript') {
        if (this.loadedResources.has(src)) {
          return Promise.resolve();
        }
        
        if (this.loadingPromises.has(src)) {
          return this.loadingPromises.get(src);
        }
        
        const promise = new Promise((resolve, reject) => {
          const script = document.createElement('script');
          script.src = src;
          script.type = type;
          script.async = true;
          
          script.onload = () => {
            this.loadedResources.add(src);
            resolve();
          };
          
          script.onerror = () => {
            reject(new Error(`Failed to load JS: ${src}`));
          };
          
          document.head.appendChild(script);
        });
        
        this.loadingPromises.set(src, promise);
        return promise;
      }
      
      // 预加载图片
      preloadImage(src) {
        if (this.loadedResources.has(src)) {
          return Promise.resolve();
        }
        
        return new Promise((resolve, reject) => {
          const img = new Image();
          img.onload = () => {
            this.loadedResources.add(src);
            resolve();
          };
          img.onerror = () => {
            reject(new Error(`Failed to preload image: ${src}`));
          };
          img.src = src;
        });
      }
      
      // 批量预加载资源
      async preloadResources(resources) {
        const promises = resources.map(resource => {
          switch (resource.type) {
            case 'css':
              return this.loadCSS(resource.url, resource.media);
            case 'js':
              return this.loadJS(resource.url, resource.scriptType);
            case 'image':
              return this.preloadImage(resource.url);
            default:
              return Promise.resolve();
          }
        });
        
        return Promise.allSettled(promises);
      }
    }
    
    // 创建资源加载器实例
    const resourceLoader = new ResourceLoader();
    
    // 页面加载完成后预加载非关键资源
    window.addEventListener('load', () => {
      const nonCriticalResources = [
        { type: 'css', url: '/css/animations.css' },
        { type: 'css', url: '/css/print.css', media: 'print' },
        { type: 'js', url: '/js/analytics.js' },
        { type: 'image', url: '/images/gallery-1.jpg' },
        { type: 'image', url: '/images/gallery-2.jpg' }
      ];
      
      resourceLoader.preloadResources(nonCriticalResources)
        .then(results => {
          console.log('Non-critical resources loaded:', results);
        });
    });
  </script>
  
  <!-- 主要 JavaScript 文件 -->
  <script src="/js/bootstrap.bundle.min.js" defer></script>
  <script type="module" src="/js/app.js"></script>
</body>
</html>

2. 缓存策略优化

// cache-strategy.js
// 缓存策略管理器

class CacheStrategyManager {
  constructor() {
    this.cacheVersion = '1.0.0';
    this.staticCacheName = `bootstrap-static-${this.cacheVersion}`;
    this.dynamicCacheName = `bootstrap-dynamic-${this.cacheVersion}`;
    this.imageCacheName = `bootstrap-images-${this.cacheVersion}`;
    
    this.staticAssets = [
      '/css/bootstrap.min.css',
      '/css/custom.css',
      '/js/bootstrap.bundle.min.js',
      '/js/app.js',
      '/fonts/custom-font.woff2',
      '/images/logo.svg'
    ];
    
    this.init();
  }
  
  // 初始化缓存策略
  init() {
    if ('serviceWorker' in navigator) {
      this.registerServiceWorker();
    }
    
    // 设置内存缓存
    this.setupMemoryCache();
    
    // 设置本地存储缓存
    this.setupLocalStorageCache();
  }
  
  // 注册 Service Worker
  async registerServiceWorker() {
    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);
    }
  }
  
  // 设置内存缓存
  setupMemoryCache() {
    this.memoryCache = new Map();
    this.memoryCacheSize = 0;
    this.maxMemoryCacheSize = 50 * 1024 * 1024; // 50MB
  }
  
  // 内存缓存操作
  setMemoryCache(key, data, size) {
    // 检查缓存大小限制
    if (this.memoryCacheSize + size > this.maxMemoryCacheSize) {
      this.clearOldMemoryCache();
    }
    
    this.memoryCache.set(key, {
      data,
      size,
      timestamp: Date.now()
    });
    
    this.memoryCacheSize += size;
  }
  
  getMemoryCache(key) {
    const cached = this.memoryCache.get(key);
    if (cached) {
      // 更新访问时间
      cached.timestamp = Date.now();
      return cached.data;
    }
    return null;
  }
  
  // 清理旧的内存缓存
  clearOldMemoryCache() {
    const entries = Array.from(this.memoryCache.entries());
    entries.sort((a, b) => a[1].timestamp - b[1].timestamp);
    
    // 删除最旧的 25% 缓存
    const deleteCount = Math.floor(entries.length * 0.25);
    for (let i = 0; i < deleteCount; i++) {
      const [key, value] = entries[i];
      this.memoryCache.delete(key);
      this.memoryCacheSize -= value.size;
    }
  }
  
  // 设置本地存储缓存
  setupLocalStorageCache() {
    this.localStoragePrefix = 'bootstrap_cache_';
    this.maxLocalStorageSize = 5 * 1024 * 1024; // 5MB
  }
  
  // 本地存储缓存操作
  setLocalStorageCache(key, data, expiry = 24 * 60 * 60 * 1000) {
    try {
      const cacheData = {
        data,
        timestamp: Date.now(),
        expiry: Date.now() + expiry
      };
      
      const serialized = JSON.stringify(cacheData);
      const cacheKey = this.localStoragePrefix + key;
      
      // 检查存储空间
      if (this.getLocalStorageSize() + serialized.length > this.maxLocalStorageSize) {
        this.clearOldLocalStorageCache();
      }
      
      localStorage.setItem(cacheKey, serialized);
    } catch (error) {
      console.warn('Local storage cache failed:', error);
    }
  }
  
  getLocalStorageCache(key) {
    try {
      const cacheKey = this.localStoragePrefix + key;
      const cached = localStorage.getItem(cacheKey);
      
      if (cached) {
        const cacheData = JSON.parse(cached);
        
        // 检查是否过期
        if (Date.now() < cacheData.expiry) {
          return cacheData.data;
        } else {
          localStorage.removeItem(cacheKey);
        }
      }
    } catch (error) {
      console.warn('Local storage cache read failed:', error);
    }
    
    return null;
  }
  
  // 获取本地存储使用大小
  getLocalStorageSize() {
    let total = 0;
    for (let key in localStorage) {
      if (key.startsWith(this.localStoragePrefix)) {
        total += localStorage[key].length;
      }
    }
    return total;
  }
  
  // 清理旧的本地存储缓存
  clearOldLocalStorageCache() {
    const keys = [];
    for (let key in localStorage) {
      if (key.startsWith(this.localStoragePrefix)) {
        try {
          const data = JSON.parse(localStorage[key]);
          keys.push({ key, timestamp: data.timestamp });
        } catch (error) {
          // 删除损坏的缓存
          localStorage.removeItem(key);
        }
      }
    }
    
    // 按时间排序,删除最旧的
    keys.sort((a, b) => a.timestamp - b.timestamp);
    const deleteCount = Math.floor(keys.length * 0.3);
    
    for (let i = 0; i < deleteCount; i++) {
      localStorage.removeItem(keys[i].key);
    }
  }
  
  // 显示更新通知
  showUpdateNotification() {
    const notification = document.createElement('div');
    notification.className = 'alert alert-info position-fixed';
    notification.style.cssText = `
      top: 20px;
      left: 50%;
      transform: translateX(-50%);
      z-index: 9999;
      min-width: 300px;
    `;
    
    notification.innerHTML = `
      <div class="d-flex align-items-center">
        <div class="flex-grow-1">
          <strong>应用已更新</strong><br>
          <small>点击刷新以获取最新版本</small>
        </div>
        <button class="btn btn-sm btn-primary ms-2" onclick="window.location.reload()">
          刷新
        </button>
        <button class="btn btn-sm btn-outline-secondary ms-1" onclick="this.parentElement.parentElement.remove()">
          ×
        </button>
      </div>
    `;
    
    document.body.appendChild(notification);
  }
  
  // 清理所有缓存
  clearAllCache() {
    // 清理内存缓存
    this.memoryCache.clear();
    this.memoryCacheSize = 0;
    
    // 清理本地存储缓存
    for (let key in localStorage) {
      if (key.startsWith(this.localStoragePrefix)) {
        localStorage.removeItem(key);
      }
    }
    
    // 清理 Service Worker 缓存
    if ('caches' in window) {
      caches.keys().then(cacheNames => {
        return Promise.all(
          cacheNames.map(cacheName => {
            if (cacheName.startsWith('bootstrap-')) {
              return caches.delete(cacheName);
            }
          })
        );
      });
    }
  }
}

// Service Worker 代码
const serviceWorkerCode = `
// sw.js
// Service Worker 缓存策略

const CACHE_VERSION = '1.0.0';
const STATIC_CACHE = \`bootstrap-static-\${CACHE_VERSION}\`;
const DYNAMIC_CACHE = \`bootstrap-dynamic-\${CACHE_VERSION}\`;
const IMAGE_CACHE = \`bootstrap-images-\${CACHE_VERSION}\`;

const STATIC_ASSETS = [
  '/',
  '/css/bootstrap.min.css',
  '/css/custom.css',
  '/js/bootstrap.bundle.min.js',
  '/js/app.js',
  '/fonts/custom-font.woff2',
  '/images/logo.svg'
];

// 安装事件
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(STATIC_CACHE)
      .then(cache => {
        return cache.addAll(STATIC_ASSETS);
      })
      .then(() => {
        return self.skipWaiting();
      })
  );
});

// 激活事件
self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys()
      .then(cacheNames => {
        return Promise.all(
          cacheNames.map(cacheName => {
            if (cacheName.startsWith('bootstrap-') && 
                cacheName !== STATIC_CACHE && 
                cacheName !== DYNAMIC_CACHE && 
                cacheName !== IMAGE_CACHE) {
              return caches.delete(cacheName);
            }
          })
        );
      })
      .then(() => {
        return self.clients.claim();
      })
  );
});

// 拦截请求
self.addEventListener('fetch', event => {
  const { request } = event;
  const url = new URL(request.url);
  
  // 静态资源:缓存优先
  if (STATIC_ASSETS.includes(url.pathname)) {
    event.respondWith(
      caches.match(request)
        .then(response => {
          return response || fetch(request)
            .then(fetchResponse => {
              const responseClone = fetchResponse.clone();
              caches.open(STATIC_CACHE)
                .then(cache => {
                  cache.put(request, responseClone);
                });
              return fetchResponse;
            });
        })
    );
    return;
  }
  
  // 图片资源:缓存优先,带过期时间
  if (request.destination === 'image') {
    event.respondWith(
      caches.match(request)
        .then(response => {
          if (response) {
            // 检查缓存时间(7天)
            const cachedDate = new Date(response.headers.get('date'));
            const now = new Date();
            const daysDiff = (now - cachedDate) / (1000 * 60 * 60 * 24);
            
            if (daysDiff < 7) {
              return response;
            }
          }
          
          return fetch(request)
            .then(fetchResponse => {
              if (fetchResponse.ok) {
                const responseClone = fetchResponse.clone();
                caches.open(IMAGE_CACHE)
                  .then(cache => {
                    cache.put(request, responseClone);
                  });
              }
              return fetchResponse;
            })
            .catch(() => {
              // 网络失败时返回缓存
              return response;
            });
        })
    );
    return;
  }
  
  // API 请求:网络优先
  if (url.pathname.startsWith('/api/')) {
    event.respondWith(
      fetch(request)
        .then(response => {
          if (response.ok) {
            const responseClone = response.clone();
            caches.open(DYNAMIC_CACHE)
              .then(cache => {
                cache.put(request, responseClone);
              });
          }
          return response;
        })
        .catch(() => {
          return caches.match(request);
        })
    );
    return;
  }
  
  // 其他请求:网络优先
  event.respondWith(
    fetch(request)
      .catch(() => {
        return caches.match(request);
      })
  );
});
`;

// 创建全局实例
const cacheStrategyManager = new CacheStrategyManager();

// 导出
export default cacheStrategyManager;

移动端性能优化

1. 移动端特定优化

// mobile-optimization.js
// 移动端性能优化管理器

class MobileOptimizationManager {
  constructor() {
    this.isMobile = this.detectMobile();
    this.isLowEndDevice = this.detectLowEndDevice();
    this.connectionType = this.getConnectionType();
    
    this.init();
  }
  
  // 检测移动设备
  detectMobile() {
    return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ||
           window.innerWidth <= 768;
  }
  
  // 检测低端设备
  detectLowEndDevice() {
    // 基于硬件并发数和内存判断
    const cores = navigator.hardwareConcurrency || 1;
    const memory = navigator.deviceMemory || 1;
    
    return cores <= 2 || memory <= 2;
  }
  
  // 获取网络连接类型
  getConnectionType() {
    if ('connection' in navigator) {
      return navigator.connection.effectiveType || 'unknown';
    }
    return 'unknown';
  }
  
  // 初始化移动端优化
  init() {
    if (this.isMobile) {
      this.optimizeForMobile();
    }
    
    if (this.isLowEndDevice) {
      this.optimizeForLowEndDevice();
    }
    
    this.optimizeForConnection();
    this.setupPerformanceMonitoring();
  }
  
  // 移动端优化
  optimizeForMobile() {
    // 禁用悬停效果
    this.disableHoverEffects();
    
    // 优化触摸事件
    this.optimizeTouchEvents();
    
    // 优化滚动性能
    this.optimizeScrolling();
    
    // 减少动画
    this.reduceAnimations();
    
    // 优化字体加载
    this.optimizeFontLoading();
  }
  
  // 禁用悬停效果
  disableHoverEffects() {
    const style = document.createElement('style');
    style.textContent = `
      @media (hover: none) {
        .btn:hover,
        .card:hover,
        .nav-link:hover,
        .dropdown-item:hover {
          transform: none !important;
          box-shadow: none !important;
          background-color: inherit !important;
        }
      }
    `;
    document.head.appendChild(style);
  }
  
  // 优化触摸事件
  optimizeTouchEvents() {
    // 添加触摸反馈
    document.addEventListener('touchstart', (e) => {
      const target = e.target.closest('.btn, .card, .nav-link');
      if (target) {
        target.style.opacity = '0.8';
        target.style.transform = 'scale(0.98)';
      }
    }, { passive: true });
    
    document.addEventListener('touchend', (e) => {
      const target = e.target.closest('.btn, .card, .nav-link');
      if (target) {
        setTimeout(() => {
          target.style.opacity = '';
          target.style.transform = '';
        }, 150);
      }
    }, { passive: true });
    
    // 防止双击缩放
    document.addEventListener('touchend', (e) => {
      const now = Date.now();
      if (this.lastTouchEnd && now - this.lastTouchEnd < 300) {
        e.preventDefault();
      }
      this.lastTouchEnd = now;
    }, { passive: false });
  }
  
  // 优化滚动性能
  optimizeScrolling() {
    // 使用 CSS 优化滚动
    const style = document.createElement('style');
    style.textContent = `
      * {
        -webkit-overflow-scrolling: touch;
      }
      
      .scroll-container {
        transform: translateZ(0);
        will-change: scroll-position;
      }
      
      .fixed-element {
        transform: translateZ(0);
        will-change: transform;
      }
    `;
    document.head.appendChild(style);
    
    // 添加滚动容器类
    document.querySelectorAll('.overflow-auto, .overflow-scroll').forEach(el => {
      el.classList.add('scroll-container');
    });
    
    // 添加固定元素类
    document.querySelectorAll('.fixed-top, .fixed-bottom, .sticky-top').forEach(el => {
      el.classList.add('fixed-element');
    });
  }
  
  // 减少动画
  reduceAnimations() {
    if (this.isLowEndDevice || this.connectionType === 'slow-2g' || this.connectionType === '2g') {
      const style = document.createElement('style');
      style.textContent = `
        *,
        *::before,
        *::after {
          animation-duration: 0.01ms !important;
          animation-iteration-count: 1 !important;
          transition-duration: 0.01ms !important;
          scroll-behavior: auto !important;
        }
        
        .fade {
          transition: none !important;
        }
        
        .collapse {
          transition: none !important;
        }
      `;
      document.head.appendChild(style);
    }
  }
  
  // 优化字体加载
  optimizeFontLoading() {
    // 使用 font-display: swap
    const style = document.createElement('style');
    style.textContent = `
      @font-face {
        font-family: 'CustomFont';
        src: url('/fonts/custom-font.woff2') format('woff2');
        font-display: swap;
      }
    `;
    document.head.appendChild(style);
    
    // 预加载关键字体
    if (this.connectionType !== 'slow-2g' && this.connectionType !== '2g') {
      const fontLink = document.createElement('link');
      fontLink.rel = 'preload';
      fontLink.href = '/fonts/custom-font.woff2';
      fontLink.as = 'font';
      fontLink.type = 'font/woff2';
      fontLink.crossOrigin = 'anonymous';
      document.head.appendChild(fontLink);
    }
  }
  
  // 低端设备优化
  optimizeForLowEndDevice() {
    // 减少 DOM 操作
    this.batchDOMUpdates();
    
    // 简化样式
    this.simplifyStyles();
    
    // 减少内存使用
    this.reduceMemoryUsage();
  }
  
  // 批量 DOM 更新
  batchDOMUpdates() {
    this.domUpdateQueue = [];
    this.domUpdateScheduled = false;
    
    this.queueDOMUpdate = (callback) => {
      this.domUpdateQueue.push(callback);
      
      if (!this.domUpdateScheduled) {
        this.domUpdateScheduled = true;
        requestAnimationFrame(() => {
          this.domUpdateQueue.forEach(callback => callback());
          this.domUpdateQueue = [];
          this.domUpdateScheduled = false;
        });
      }
    };
  }
  
  // 简化样式
  simplifyStyles() {
    const style = document.createElement('style');
    style.textContent = `
      .card {
        box-shadow: 0 1px 3px rgba(0,0,0,0.12) !important;
      }
      
      .btn {
        box-shadow: none !important;
      }
      
      .dropdown-menu {
        box-shadow: 0 2px 4px rgba(0,0,0,0.1) !important;
      }
      
      .modal {
        backdrop-filter: none !important;
      }
    `;
    document.head.appendChild(style);
  }
  
  // 减少内存使用
  reduceMemoryUsage() {
    // 定期清理未使用的事件监听器
    setInterval(() => {
      this.cleanupEventListeners();
    }, 60000); // 每分钟清理一次
    
    // 限制图片质量
    this.limitImageQuality();
  }
  
  // 清理事件监听器
  cleanupEventListeners() {
    // 移除不可见元素的事件监听器
    document.querySelectorAll('[data-cleanup-listeners]').forEach(el => {
      if (!el.offsetParent) {
        // 元素不可见,移除事件监听器
        const newEl = el.cloneNode(true);
        el.parentNode.replaceChild(newEl, el);
      }
    });
  }
  
  // 限制图片质量
  limitImageQuality() {
    document.querySelectorAll('img').forEach(img => {
      if (!img.dataset.optimized) {
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');
        
        img.onload = () => {
          canvas.width = img.naturalWidth;
          canvas.height = img.naturalHeight;
          
          ctx.drawImage(img, 0, 0);
          
          // 降低质量
          const optimizedDataUrl = canvas.toDataURL('image/jpeg', 0.7);
          img.src = optimizedDataUrl;
          img.dataset.optimized = 'true';
        };
      }
    });
  }
  
  // 网络连接优化
  optimizeForConnection() {
    if ('connection' in navigator) {
      const connection = navigator.connection;
      
      // 监听网络变化
      connection.addEventListener('change', () => {
        this.connectionType = connection.effectiveType;
        this.adjustForConnection();
      });
      
      this.adjustForConnection();
    }
  }
  
  // 根据网络调整
  adjustForConnection() {
    switch (this.connectionType) {
      case 'slow-2g':
      case '2g':
        this.enableDataSaverMode();
        break;
      case '3g':
        this.enableReducedQualityMode();
        break;
      case '4g':
      default:
        this.enableNormalMode();
        break;
    }
  }
  
  // 数据节省模式
  enableDataSaverMode() {
    // 禁用图片加载
    document.querySelectorAll('img[data-src]').forEach(img => {
      img.style.display = 'none';
    });
    
    // 禁用视频自动播放
    document.querySelectorAll('video').forEach(video => {
      video.autoplay = false;
      video.preload = 'none';
    });
    
    // 显示数据节省提示
    this.showDataSaverNotification();
  }
  
  // 降低质量模式
  enableReducedQualityMode() {
    // 使用低质量图片
    document.querySelectorAll('img[data-src-low]').forEach(img => {
      img.src = img.dataset.srcLow;
    });
  }
  
  // 正常模式
  enableNormalMode() {
    // 恢复正常图片
    document.querySelectorAll('img[data-src]').forEach(img => {
      img.src = img.dataset.src;
      img.style.display = '';
    });
  }
  
  // 显示数据节省通知
  showDataSaverNotification() {
    const notification = document.createElement('div');
    notification.className = 'alert alert-warning position-fixed';
    notification.style.cssText = `
      bottom: 20px;
      left: 20px;
      right: 20px;
      z-index: 9999;
    `;
    
    notification.innerHTML = `
      <div class="d-flex align-items-center">
        <div class="flex-grow-1">
          <strong>数据节省模式</strong><br>
          <small>检测到慢速网络,已启用数据节省模式</small>
        </div>
        <button class="btn btn-sm btn-outline-warning ms-2" onclick="this.parentElement.parentElement.remove()">
          ×
        </button>
      </div>
    `;
    
    document.body.appendChild(notification);
    
    // 5秒后自动隐藏
    setTimeout(() => {
      if (notification.parentElement) {
        notification.remove();
      }
    }, 5000);
  }
  
  // 性能监控
  setupPerformanceMonitoring() {
    // 监控 FPS
    this.monitorFPS();
    
    // 监控内存使用
    this.monitorMemoryUsage();
    
    // 监控网络性能
    this.monitorNetworkPerformance();
  }
  
  // 监控 FPS
  monitorFPS() {
    let lastTime = performance.now();
    let frameCount = 0;
    let fps = 60;
    
    const measureFPS = (currentTime) => {
      frameCount++;
      
      if (currentTime - lastTime >= 1000) {
        fps = Math.round((frameCount * 1000) / (currentTime - lastTime));
        frameCount = 0;
        lastTime = currentTime;
        
        // 如果 FPS 过低,启用性能优化
        if (fps < 30) {
          this.enablePerformanceMode();
        }
      }
      
      requestAnimationFrame(measureFPS);
    };
    
    requestAnimationFrame(measureFPS);
  }
  
  // 监控内存使用
  monitorMemoryUsage() {
    if ('memory' in performance) {
      setInterval(() => {
        const memory = performance.memory;
        const usedPercent = (memory.usedJSHeapSize / memory.jsHeapSizeLimit) * 100;
        
        // 如果内存使用超过 80%,触发清理
        if (usedPercent > 80) {
          this.triggerMemoryCleanup();
        }
      }, 10000); // 每10秒检查一次
    }
  }
  
  // 监控网络性能
  monitorNetworkPerformance() {
    // 使用 Navigation Timing API
    window.addEventListener('load', () => {
      const navigation = performance.getEntriesByType('navigation')[0];
      const loadTime = navigation.loadEventEnd - navigation.loadEventStart;
      
      // 如果加载时间过长,启用优化
      if (loadTime > 3000) {
        this.enableSlowNetworkOptimizations();
      }
    });
  }
  
  // 启用性能模式
  enablePerformanceMode() {
    if (!this.performanceModeEnabled) {
      this.performanceModeEnabled = true;
      
      // 减少动画
      this.reduceAnimations();
      
      // 降低渲染质量
      document.body.style.transform = 'translateZ(0)';
      document.body.style.backfaceVisibility = 'hidden';
    }
  }
  
  // 触发内存清理
  triggerMemoryCleanup() {
    // 清理缓存
    if (window.cacheStrategyManager) {
      window.cacheStrategyManager.clearOldMemoryCache();
    }
    
    // 强制垃圾回收(如果支持)
    if (window.gc) {
      window.gc();
    }
  }
  
  // 慢速网络优化
  enableSlowNetworkOptimizations() {
    // 延迟加载非关键资源
    this.deferNonCriticalResources();
    
    // 压缩图片
    this.compressImages();
  }
  
  // 延迟加载非关键资源
  deferNonCriticalResources() {
    // 延迟加载分析脚本
    setTimeout(() => {
      const analyticsScript = document.createElement('script');
      analyticsScript.src = '/js/analytics.js';
      analyticsScript.async = true;
      document.head.appendChild(analyticsScript);
    }, 5000);
  }
  
  // 压缩图片
  compressImages() {
    document.querySelectorAll('img').forEach(img => {
      if (!img.dataset.compressed) {
        // 添加压缩参数
        if (img.src.includes('?')) {
          img.src += '&quality=70&format=webp';
        } else {
          img.src += '?quality=70&format=webp';
        }
        img.dataset.compressed = 'true';
      }
    });
  }
}

// 创建全局实例
const mobileOptimizationManager = new MobileOptimizationManager();

// 导出
export default mobileOptimizationManager;

最佳实践与开发规范

1. 性能开发规范

// performance-guidelines.js
// 性能开发规范和最佳实践

class PerformanceGuidelines {
  constructor() {
    this.performanceRules = {
      // CSS 规范
      css: {
        maxFileSize: 100 * 1024, // 100KB
        maxSelectors: 4000,
        maxNestingDepth: 4,
        avoidExpensiveSelectors: [
          '*',
          '[attribute^="value"]',
          ':nth-child(n+3)',
          'div > div > div > div'
        ]
      },
      
      // JavaScript 规范
      javascript: {
        maxFileSize: 200 * 1024, // 200KB
        maxFunctionComplexity: 10,
        maxDOMQueries: 5,
        avoidPatterns: [
          'document.write',
          'eval',
          'with',
          'innerHTML in loops'
        ]
      },
      
      // 图片规范
      images: {
        maxFileSize: 500 * 1024, // 500KB
        preferredFormats: ['webp', 'avif', 'jpg', 'png'],
        maxDimensions: { width: 1920, height: 1080 },
        compressionQuality: 0.8
      },
      
      // 网络规范
      network: {
        maxRequests: 50,
        maxTotalSize: 2 * 1024 * 1024, // 2MB
        timeToFirstByte: 200, // ms
        firstContentfulPaint: 1500 // ms
      }
    };
    
    this.init();
  }
  
  // 初始化性能检查
  init() {
    this.setupPerformanceObserver();
    this.setupResourceMonitoring();
    this.setupUserTimingAPI();
    this.createPerformanceDashboard();
  }
  
  // 设置性能观察器
  setupPerformanceObserver() {
    if ('PerformanceObserver' in window) {
      // 监控 LCP (Largest Contentful Paint)
      const lcpObserver = new PerformanceObserver((list) => {
        const entries = list.getEntries();
        const lastEntry = entries[entries.length - 1];
        this.recordMetric('LCP', lastEntry.startTime);
      });
      lcpObserver.observe({ entryTypes: ['largest-contentful-paint'] });
      
      // 监控 FID (First Input Delay)
      const fidObserver = new PerformanceObserver((list) => {
        const entries = list.getEntries();
        entries.forEach(entry => {
          this.recordMetric('FID', entry.processingStart - entry.startTime);
        });
      });
      fidObserver.observe({ entryTypes: ['first-input'] });
      
      // 监控 CLS (Cumulative Layout Shift)
      const clsObserver = new PerformanceObserver((list) => {
        let clsValue = 0;
        const entries = list.getEntries();
        entries.forEach(entry => {
          if (!entry.hadRecentInput) {
            clsValue += entry.value;
          }
        });
        this.recordMetric('CLS', clsValue);
      });
      clsObserver.observe({ entryTypes: ['layout-shift'] });
      
      // 监控长任务
      const longTaskObserver = new PerformanceObserver((list) => {
        const entries = list.getEntries();
        entries.forEach(entry => {
          this.recordMetric('Long Task', entry.duration);
          this.analyzeLongTask(entry);
        });
      });
      longTaskObserver.observe({ entryTypes: ['longtask'] });
    }
  }
  
  // 设置资源监控
  setupResourceMonitoring() {
    // 监控资源加载
    const resourceObserver = new PerformanceObserver((list) => {
      const entries = list.getEntries();
      entries.forEach(entry => {
        this.analyzeResource(entry);
      });
    });
    resourceObserver.observe({ entryTypes: ['resource'] });
    
    // 监控导航时间
    window.addEventListener('load', () => {
      const navigation = performance.getEntriesByType('navigation')[0];
      this.analyzeNavigation(navigation);
    });
  }
  
  // 设置用户时间 API
  setupUserTimingAPI() {
    this.timingMarks = new Map();
    
    // 创建便捷方法
    window.performanceMark = (name) => {
      performance.mark(name);
      this.timingMarks.set(name, performance.now());
    };
    
    window.performanceMeasure = (name, startMark, endMark) => {
      performance.measure(name, startMark, endMark);
      const measure = performance.getEntriesByName(name, 'measure')[0];
      this.recordMetric(name, measure.duration);
    };
  }
  
  // 分析长任务
  analyzeLongTask(entry) {
    const taskInfo = {
      duration: entry.duration,
      startTime: entry.startTime,
      attribution: entry.attribution
    };
    
    // 如果任务超过 100ms,记录警告
    if (entry.duration > 100) {
      console.warn('Long task detected:', taskInfo);
      this.reportPerformanceIssue('long-task', taskInfo);
    }
  }
  
  // 分析资源
  analyzeResource(entry) {
    const resourceInfo = {
      name: entry.name,
      type: this.getResourceType(entry),
      size: entry.transferSize || entry.encodedBodySize,
      duration: entry.duration,
      startTime: entry.startTime
    };
    
    // 检查资源大小
    this.checkResourceSize(resourceInfo);
    
    // 检查加载时间
    this.checkResourceTiming(resourceInfo);
    
    // 检查缓存效率
    this.checkCacheEfficiency(entry);
  }
  
  // 获取资源类型
  getResourceType(entry) {
    if (entry.initiatorType) {
      return entry.initiatorType;
    }
    
    const url = new URL(entry.name);
    const extension = url.pathname.split('.').pop().toLowerCase();
    
    const typeMap = {
      'css': 'stylesheet',
      'js': 'script',
      'jpg': 'image',
      'jpeg': 'image',
      'png': 'image',
      'gif': 'image',
      'webp': 'image',
      'svg': 'image',
      'woff': 'font',
      'woff2': 'font',
      'ttf': 'font',
      'eot': 'font'
    };
    
    return typeMap[extension] || 'other';
  }
  
  // 检查资源大小
  checkResourceSize(resourceInfo) {
    const { type, size, name } = resourceInfo;
    let maxSize;
    
    switch (type) {
      case 'stylesheet':
        maxSize = this.performanceRules.css.maxFileSize;
        break;
      case 'script':
        maxSize = this.performanceRules.javascript.maxFileSize;
        break;
      case 'image':
        maxSize = this.performanceRules.images.maxFileSize;
        break;
      default:
        return;
    }
    
    if (size > maxSize) {
      this.reportPerformanceIssue('large-resource', {
        name,
        type,
        size,
        maxSize,
        recommendation: this.getOptimizationRecommendation(type)
      });
    }
  }
  
  // 检查资源时间
  checkResourceTiming(resourceInfo) {
    const { duration, name, type } = resourceInfo;
    
    // 设置不同资源类型的时间阈值
    const timeThresholds = {
      'stylesheet': 500,
      'script': 1000,
      'image': 2000,
      'font': 1000
    };
    
    const threshold = timeThresholds[type] || 1000;
    
    if (duration > threshold) {
      this.reportPerformanceIssue('slow-resource', {
        name,
        type,
        duration,
        threshold,
        recommendation: 'Consider optimizing or using CDN'
      });
    }
  }
  
  // 检查缓存效率
  checkCacheEfficiency(entry) {
    const transferSize = entry.transferSize || 0;
    const encodedBodySize = entry.encodedBodySize || 0;
    
    // 如果传输大小为 0,说明从缓存加载
    const fromCache = transferSize === 0 && encodedBodySize > 0;
    
    // 如果传输大小远小于编码大小,说明使用了压缩
    const compressionRatio = transferSize / encodedBodySize;
    
    this.recordMetric('Cache Hit', fromCache ? 1 : 0);
    if (!fromCache && compressionRatio > 0.8) {
      this.reportPerformanceIssue('poor-compression', {
        name: entry.name,
        compressionRatio,
        recommendation: 'Enable gzip/brotli compression'
      });
    }
  }
  
  // 分析导航时间
  analyzeNavigation(navigation) {
    const timings = {
      'DNS Lookup': navigation.domainLookupEnd - navigation.domainLookupStart,
      'TCP Connection': navigation.connectEnd - navigation.connectStart,
      'TLS Handshake': navigation.secureConnectionStart > 0 ? 
        navigation.connectEnd - navigation.secureConnectionStart : 0,
      'Request': navigation.responseStart - navigation.requestStart,
      'Response': navigation.responseEnd - navigation.responseStart,
      'DOM Processing': navigation.domContentLoadedEventStart - navigation.responseEnd,
      'Resource Loading': navigation.loadEventStart - navigation.domContentLoadedEventEnd
    };
    
    Object.entries(timings).forEach(([name, duration]) => {
      this.recordMetric(name, duration);
    });
    
    // 检查关键时间指标
    const ttfb = navigation.responseStart - navigation.requestStart;
    if (ttfb > this.performanceRules.network.timeToFirstByte) {
      this.reportPerformanceIssue('slow-ttfb', {
        ttfb,
        threshold: this.performanceRules.network.timeToFirstByte,
        recommendation: 'Optimize server response time'
      });
    }
  }
  
  // 获取优化建议
  getOptimizationRecommendation(type) {
    const recommendations = {
      'stylesheet': 'Use CSS minification, remove unused styles, consider critical CSS',
      'script': 'Use JavaScript minification, code splitting, tree shaking',
      'image': 'Use modern formats (WebP, AVIF), optimize compression, implement lazy loading',
      'font': 'Use font-display: swap, subset fonts, preload critical fonts'
    };
    
    return recommendations[type] || 'Consider optimization techniques';
  }
  
  // 记录性能指标
  recordMetric(name, value) {
    if (!this.metrics) {
      this.metrics = new Map();
    }
    
    if (!this.metrics.has(name)) {
      this.metrics.set(name, []);
    }
    
    this.metrics.get(name).push({
      value,
      timestamp: Date.now()
    });
    
    // 更新仪表板
    this.updateDashboard(name, value);
  }
  
  // 报告性能问题
  reportPerformanceIssue(type, details) {
    const issue = {
      type,
      details,
      timestamp: Date.now(),
      severity: this.getSeverity(type, details)
    };
    
    console.warn('Performance issue detected:', issue);
    
    // 发送到分析服务
    this.sendToAnalytics(issue);
    
    // 显示开发者通知
    if (this.isDevelopmentMode()) {
      this.showDeveloperNotification(issue);
    }
  }
  
  // 获取问题严重程度
  getSeverity(type, details) {
    const severityMap = {
      'long-task': details.duration > 500 ? 'high' : 'medium',
      'large-resource': details.size > details.maxSize * 2 ? 'high' : 'medium',
      'slow-resource': details.duration > details.threshold * 2 ? 'high' : 'medium',
      'poor-compression': 'low',
      'slow-ttfb': details.ttfb > 1000 ? 'high' : 'medium'
    };
    
    return severityMap[type] || 'low';
  }
  
  // 检查是否为开发模式
  isDevelopmentMode() {
    return location.hostname === 'localhost' || 
           location.hostname === '127.0.0.1' ||
           location.hostname.includes('dev');
  }
  
  // 显示开发者通知
  showDeveloperNotification(issue) {
    const notification = document.createElement('div');
    notification.className = `alert alert-${this.getSeverityClass(issue.severity)} position-fixed`;
    notification.style.cssText = `
      top: 20px;
      right: 20px;
      max-width: 400px;
      z-index: 10000;
      font-size: 12px;
    `;
    
    notification.innerHTML = `
      <div class="d-flex align-items-start">
        <div class="flex-grow-1">
          <strong>Performance Issue: ${issue.type}</strong><br>
          <small>${JSON.stringify(issue.details, null, 2)}</small>
        </div>
        <button class="btn btn-sm btn-outline-secondary ms-2" onclick="this.parentElement.parentElement.remove()">
          ×
        </button>
      </div>
    `;
    
    document.body.appendChild(notification);
    
    // 10秒后自动隐藏
    setTimeout(() => {
      if (notification.parentElement) {
        notification.remove();
      }
    }, 10000);
  }
  
  // 获取严重程度对应的 Bootstrap 类
  getSeverityClass(severity) {
    const classMap = {
      'high': 'danger',
      'medium': 'warning',
      'low': 'info'
    };
    
    return classMap[severity] || 'info';
  }
  
  // 发送到分析服务
  sendToAnalytics(issue) {
    // 这里可以集成 Google Analytics、Sentry 等服务
    if (typeof gtag !== 'undefined') {
      gtag('event', 'performance_issue', {
        event_category: 'Performance',
        event_label: issue.type,
        value: issue.severity === 'high' ? 3 : issue.severity === 'medium' ? 2 : 1
      });
    }
  }
  
  // 创建性能仪表板
  createPerformanceDashboard() {
    if (!this.isDevelopmentMode()) {
      return;
    }
    
    const dashboard = document.createElement('div');
    dashboard.id = 'performance-dashboard';
    dashboard.style.cssText = `
      position: fixed;
      bottom: 20px;
      left: 20px;
      width: 300px;
      background: rgba(0, 0, 0, 0.9);
      color: white;
      padding: 15px;
      border-radius: 8px;
      font-family: monospace;
      font-size: 12px;
      z-index: 10000;
      max-height: 400px;
      overflow-y: auto;
      display: none;
    `;
    
    dashboard.innerHTML = `
      <div class="d-flex justify-content-between align-items-center mb-2">
        <strong>Performance Dashboard</strong>
        <button class="btn btn-sm btn-outline-light" onclick="this.parentElement.parentElement.style.display='none'">
          ×
        </button>
      </div>
      <div id="performance-metrics"></div>
    `;
    
    document.body.appendChild(dashboard);
    
    // 添加切换按钮
    const toggleButton = document.createElement('button');
    toggleButton.textContent = '📊';
    toggleButton.style.cssText = `
      position: fixed;
      bottom: 20px;
      left: 20px;
      width: 40px;
      height: 40px;
      border-radius: 50%;
      border: none;
      background: #007bff;
      color: white;
      font-size: 16px;
      cursor: pointer;
      z-index: 10001;
    `;
    
    toggleButton.onclick = () => {
      dashboard.style.display = dashboard.style.display === 'none' ? 'block' : 'none';
    };
    
    document.body.appendChild(toggleButton);
    
    this.dashboard = dashboard;
  }
  
  // 更新仪表板
  updateDashboard(name, value) {
    if (!this.dashboard) {
      return;
    }
    
    const metricsContainer = this.dashboard.querySelector('#performance-metrics');
    let metricElement = metricsContainer.querySelector(`[data-metric="${name}"]`);
    
    if (!metricElement) {
      metricElement = document.createElement('div');
      metricElement.setAttribute('data-metric', name);
      metricElement.style.marginBottom = '5px';
      metricsContainer.appendChild(metricElement);
    }
    
    const formattedValue = typeof value === 'number' ? 
      (value < 1 ? value.toFixed(3) : Math.round(value)) : value;
    
    metricElement.innerHTML = `<strong>${name}:</strong> ${formattedValue}${this.getUnit(name)}`;
  }
  
  // 获取指标单位
  getUnit(metricName) {
    const units = {
      'LCP': 'ms',
      'FID': 'ms',
      'CLS': '',
      'Long Task': 'ms',
      'DNS Lookup': 'ms',
      'TCP Connection': 'ms',
      'TLS Handshake': 'ms',
      'Request': 'ms',
      'Response': 'ms',
      'DOM Processing': 'ms',
      'Resource Loading': 'ms',
      'Cache Hit': ''
    };
    
    return units[metricName] || '';
  }
  
  // 生成性能报告
  generateReport() {
    const report = {
      timestamp: new Date().toISOString(),
      metrics: {},
      summary: {},
      recommendations: []
    };
    
    // 汇总指标
    this.metrics.forEach((values, name) => {
      const numericValues = values.map(v => v.value).filter(v => typeof v === 'number');
      if (numericValues.length > 0) {
        report.metrics[name] = {
          count: numericValues.length,
          average: numericValues.reduce((a, b) => a + b, 0) / numericValues.length,
          min: Math.min(...numericValues),
          max: Math.max(...numericValues),
          latest: values[values.length - 1].value
        };
      }
    });
    
    // 生成摘要
    report.summary = this.generateSummary(report.metrics);
    
    // 生成建议
    report.recommendations = this.generateRecommendations(report.metrics);
    
    return report;
  }
  
  // 生成摘要
  generateSummary(metrics) {
    const summary = {
      performance: 'good',
      issues: [],
      score: 100
    };
    
    // 检查核心 Web 指标
    if (metrics.LCP && metrics.LCP.latest > 2500) {
      summary.issues.push('LCP is too slow');
      summary.score -= 20;
    }
    
    if (metrics.FID && metrics.FID.latest > 100) {
      summary.issues.push('FID is too high');
      summary.score -= 15;
    }
    
    if (metrics.CLS && metrics.CLS.latest > 0.1) {
      summary.issues.push('CLS is too high');
      summary.score -= 15;
    }
    
    // 确定整体性能等级
    if (summary.score >= 90) {
      summary.performance = 'excellent';
    } else if (summary.score >= 70) {
      summary.performance = 'good';
    } else if (summary.score >= 50) {
      summary.performance = 'needs improvement';
    } else {
      summary.performance = 'poor';
    }
    
    return summary;
  }
  
  // 生成建议
  generateRecommendations(metrics) {
    const recommendations = [];
    
    if (metrics.LCP && metrics.LCP.latest > 2500) {
      recommendations.push({
        priority: 'high',
        category: 'LCP',
        suggestion: 'Optimize largest contentful paint by reducing server response time, optimizing images, and removing render-blocking resources'
      });
    }
    
    if (metrics['Long Task'] && metrics['Long Task'].average > 50) {
      recommendations.push({
        priority: 'medium',
        category: 'JavaScript',
        suggestion: 'Break up long tasks by using code splitting and yielding to the main thread'
      });
    }
    
    if (metrics['Cache Hit'] && metrics['Cache Hit'].average < 0.8) {
      recommendations.push({
        priority: 'medium',
        category: 'Caching',
        suggestion: 'Improve cache hit ratio by implementing proper cache headers and service worker caching'
      });
    }
    
    return recommendations;
  }
}

// 创建全局实例
const performanceGuidelines = new PerformanceGuidelines();

// 导出
export default performanceGuidelines;

2. 代码审查清单

# Bootstrap 性能优化代码审查清单

## CSS 优化检查
- [ ] 是否移除了未使用的 CSS 规则?
- [ ] 是否使用了 CSS 压缩?
- [ ] 是否避免了复杂的选择器?
- [ ] 是否使用了关键 CSS 内联?
- [ ] 是否合理使用了 CSS 自定义属性?
- [ ] 是否避免了 @import 语句?
- [ ] 是否使用了适当的 CSS 单位(rem, em, %)?

## JavaScript 优化检查
- [ ] 是否实现了代码分割?
- [ ] 是否使用了懒加载?
- [ ] 是否避免了全局变量污染?
- [ ] 是否使用了事件委托?
- [ ] 是否实现了防抖和节流?
- [ ] 是否移除了未使用的代码?
- [ ] 是否使用了现代 JavaScript 特性?

## 图片优化检查
- [ ] 是否使用了现代图片格式(WebP, AVIF)?
- [ ] 是否实现了响应式图片?
- [ ] 是否使用了图片懒加载?
- [ ] 是否优化了图片压缩质量?
- [ ] 是否提供了适当的图片尺寸?
- [ ] 是否使用了 SVG 替代简单图标?

## 网络优化检查
- [ ] 是否启用了 HTTP/2?
- [ ] 是否使用了 CDN?
- [ ] 是否实现了资源预加载?
- [ ] 是否启用了 Gzip/Brotli 压缩?
- [ ] 是否设置了适当的缓存头?
- [ ] 是否减少了 HTTP 请求数量?

## 移动端优化检查
- [ ] 是否实现了触摸友好的交互?
- [ ] 是否优化了滚动性能?
- [ ] 是否考虑了低端设备性能?
- [ ] 是否实现了网络自适应?
- [ ] 是否禁用了不必要的悬停效果?

## 可访问性检查
- [ ] 是否提供了适当的 ARIA 标签?
- [ ] 是否支持键盘导航?
- [ ] 是否有足够的颜色对比度?
- [ ] 是否提供了替代文本?
- [ ] 是否支持屏幕阅读器?

性能监控与分析

1. 性能监控工具集成

// performance-monitoring.js
// 性能监控工具集成

class PerformanceMonitoring {
  constructor() {
    this.config = {
      // Google Analytics 配置
      ga: {
        trackingId: 'GA_TRACKING_ID',
        enabled: true
      },
      
      // Web Vitals 配置
      webVitals: {
        enabled: true,
        reportAllChanges: false
      },
      
      // 自定义监控配置
      custom: {
        enabled: true,
        sampleRate: 0.1, // 10% 采样率
        endpoint: '/api/performance'
      }
    };
    
    this.init();
  }
  
  // 初始化监控
  async init() {
    // 加载 Web Vitals 库
    if (this.config.webVitals.enabled) {
      await this.loadWebVitals();
    }
    
    // 设置自定义监控
    if (this.config.custom.enabled) {
      this.setupCustomMonitoring();
    }
    
    // 设置错误监控
    this.setupErrorMonitoring();
    
    // 设置用户行为监控
    this.setupUserBehaviorMonitoring();
  }
  
  // 加载 Web Vitals
  async loadWebVitals() {
    try {
      const { getCLS, getFID, getFCP, getLCP, getTTFB } = await import('web-vitals');
      
      // 监控 CLS (Cumulative Layout Shift)
      getCLS(this.sendToAnalytics.bind(this), this.config.webVitals.reportAllChanges);
      
      // 监控 FID (First Input Delay)
      getFID(this.sendToAnalytics.bind(this));
      
      // 监控 FCP (First Contentful Paint)
      getFCP(this.sendToAnalytics.bind(this));
      
      // 监控 LCP (Largest Contentful Paint)
      getLCP(this.sendToAnalytics.bind(this), this.config.webVitals.reportAllChanges);
      
      // 监控 TTFB (Time to First Byte)
      getTTFB(this.sendToAnalytics.bind(this));
      
    } catch (error) {
      console.warn('Failed to load Web Vitals:', error);
    }
  }
  
  // 设置自定义监控
  setupCustomMonitoring() {
    // 监控页面加载时间
    window.addEventListener('load', () => {
      const navigation = performance.getEntriesByType('navigation')[0];
      const loadTime = navigation.loadEventEnd - navigation.loadEventStart;
      
      this.sendCustomMetric('page_load_time', loadTime);
    });
    
    // 监控资源加载
    const resourceObserver = new PerformanceObserver((list) => {
      const entries = list.getEntries();
      entries.forEach(entry => {
        if (Math.random() < this.config.custom.sampleRate) {
          this.sendCustomMetric('resource_load_time', {
            name: entry.name,
            duration: entry.duration,
            size: entry.transferSize
          });
        }
      });
    });
    resourceObserver.observe({ entryTypes: ['resource'] });
    
    // 监控用户交互
    this.setupInteractionMonitoring();
  }
  
  // 设置交互监控
  setupInteractionMonitoring() {
    // 监控点击事件
    document.addEventListener('click', (event) => {
      const target = event.target;
      const selector = this.getElementSelector(target);
      
      this.sendCustomMetric('user_interaction', {
        type: 'click',
        selector,
        timestamp: Date.now()
      });
    }, { passive: true });
    
    // 监控表单提交
    document.addEventListener('submit', (event) => {
      const form = event.target;
      const formId = form.id || form.className;
      
      this.sendCustomMetric('form_submission', {
        formId,
        timestamp: Date.now()
      });
    }, { passive: true });
  }
  
  // 设置错误监控
  setupErrorMonitoring() {
    // JavaScript 错误
    window.addEventListener('error', (event) => {
      this.sendErrorReport({
        type: 'javascript_error',
        message: event.message,
        filename: event.filename,
        lineno: event.lineno,
        colno: event.colno,
        stack: event.error ? event.error.stack : null
      });
    });
    
    // Promise 拒绝
    window.addEventListener('unhandledrejection', (event) => {
      this.sendErrorReport({
        type: 'unhandled_promise_rejection',
        reason: event.reason,
        stack: event.reason ? event.reason.stack : null
      });
    });
    
    // 资源加载错误
    document.addEventListener('error', (event) => {
      if (event.target !== window) {
        this.sendErrorReport({
          type: 'resource_error',
          element: event.target.tagName,
          source: event.target.src || event.target.href,
          message: 'Resource failed to load'
        });
      }
    }, true);
  }
  
  // 设置用户行为监控
  setupUserBehaviorMonitoring() {
    // 页面可见性变化
    document.addEventListener('visibilitychange', () => {
      this.sendCustomMetric('page_visibility', {
        hidden: document.hidden,
        timestamp: Date.now()
      });
    });
    
    // 页面卸载
    window.addEventListener('beforeunload', () => {
      const sessionDuration = Date.now() - this.sessionStartTime;
      this.sendCustomMetric('session_duration', sessionDuration);
    });
    
    // 记录会话开始时间
    this.sessionStartTime = Date.now();
  }
  
  // 获取元素选择器
  getElementSelector(element) {
    if (element.id) {
      return `#${element.id}`;
    }
    
    if (element.className) {
      return `.${element.className.split(' ')[0]}`;
    }
    
    return element.tagName.toLowerCase();
  }
  
  // 发送到分析服务
  sendToAnalytics(metric) {
    // 发送到 Google Analytics
    if (this.config.ga.enabled && typeof gtag !== 'undefined') {
      gtag('event', 'web_vitals', {
        event_category: 'Web Vitals',
        event_label: metric.name,
        value: Math.round(metric.value),
        custom_map: {
          metric_id: metric.id,
          metric_value: metric.value,
          metric_delta: metric.delta
        }
      });
    }
    
    // 发送到自定义端点
    this.sendCustomMetric('web_vitals', {
      name: metric.name,
      value: metric.value,
      id: metric.id,
      delta: metric.delta
    });
  }
  
  // 发送自定义指标
  sendCustomMetric(name, data) {
    if (!this.config.custom.enabled) {
      return;
    }
    
    const payload = {
      metric: name,
      data,
      timestamp: Date.now(),
      url: window.location.href,
      userAgent: navigator.userAgent,
      sessionId: this.getSessionId()
    };
    
    // 使用 sendBeacon 或 fetch 发送
    if (navigator.sendBeacon) {
      navigator.sendBeacon(
        this.config.custom.endpoint,
        JSON.stringify(payload)
      );
    } else {
      fetch(this.config.custom.endpoint, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(payload),
        keepalive: true
      }).catch(error => {
        console.warn('Failed to send metric:', error);
      });
    }
  }
  
  // 发送错误报告
  sendErrorReport(error) {
    const payload = {
      ...error,
      timestamp: Date.now(),
      url: window.location.href,
      userAgent: navigator.userAgent,
      sessionId: this.getSessionId()
    };
    
    // 发送到错误监控服务
    this.sendCustomMetric('error', payload);
    
    // 发送到 Google Analytics
    if (this.config.ga.enabled && typeof gtag !== 'undefined') {
      gtag('event', 'exception', {
        description: error.message || error.type,
        fatal: false
      });
    }
  }
  
  // 获取会话 ID
  getSessionId() {
    if (!this.sessionId) {
      this.sessionId = 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
    }
    return this.sessionId;
  }
  
  // 手动记录性能标记
  mark(name) {
    performance.mark(name);
    this.sendCustomMetric('performance_mark', {
      name,
      timestamp: performance.now()
    });
  }
  
  // 手动记录性能测量
  measure(name, startMark, endMark) {
    performance.measure(name, startMark, endMark);
    const measure = performance.getEntriesByName(name, 'measure')[0];
    
    this.sendCustomMetric('performance_measure', {
      name,
      duration: measure.duration,
      startTime: measure.startTime
    });
  }
}

// 创建全局实例
const performanceMonitoring = new PerformanceMonitoring();

// 导出便捷方法
window.perfMark = performanceMonitoring.mark.bind(performanceMonitoring);
window.perfMeasure = performanceMonitoring.measure.bind(performanceMonitoring);

// 导出
export default performanceMonitoring;

本章总结

本章深入探讨了 Bootstrap 应用的性能优化策略和最佳实践,涵盖了以下关键领域:

核心优化技术

  1. CSS 性能优化

    • 使用 PurgeCSS 移除未使用的样式
    • 自定义 Bootstrap 构建以减少文件大小
    • 实现关键 CSS 内联和异步加载
    • CSS 压缩和优化技术
  2. JavaScript 性能优化

    • 按需加载 Bootstrap 组件
    • 代码分割和懒加载策略
    • 事件委托和性能优化
    • 内存管理和清理
  3. 资源加载优化

    • 资源预加载和预连接
    • 缓存策略和 Service Worker
    • 图片优化和现代格式支持
    • 字体加载优化

移动端优化

  1. 移动设备适配

    • 低端设备性能优化
    • 网络连接自适应
    • 触摸交互优化
    • 电池和内存使用优化
  2. 响应式性能

    • 移动优先的加载策略
    • 数据节省模式
    • 自适应图片和媒体
    • 滚动性能优化

监控和分析

  1. 性能监控

    • Core Web Vitals 监控
    • 自定义性能指标
    • 错误监控和报告
    • 用户行为分析
  2. 开发工具

    • 性能仪表板
    • 代码审查清单
    • 自动化性能检测
    • 持续集成优化

最佳实践

  1. 开发规范
    • 性能预算设定
    • 代码质量标准
    • 测试和验证流程
    • 团队协作规范

通过实施这些优化策略,可以显著提升 Bootstrap 应用的性能表现,改善用户体验,并确保应用在各种设备和网络条件下都能良好运行。

练习题

基础练习

  1. CSS 优化实践

    • 使用 PurgeCSS 优化一个 Bootstrap 项目
    • 实现关键 CSS 内联
    • 测量优化前后的文件大小差异
  2. JavaScript 懒加载

    • 实现 Bootstrap 组件的按需加载
    • 创建一个懒加载管理器
    • 测量首屏加载时间的改善
  3. 缓存策略

    • 实现 Service Worker 缓存
    • 配置不同类型资源的缓存策略
    • 测试离线功能

进阶练习

  1. 移动端优化

    • 实现网络自适应加载
    • 创建低端设备优化模式
    • 测试不同网络条件下的性能
  2. 性能监控

    • 集成 Web Vitals 监控
    • 创建自定义性能仪表板
    • 实现性能预警系统
  3. 综合优化项目

    • 选择一个现有的 Bootstrap 项目
    • 应用本章所有优化技术
    • 生成详细的性能报告
    • 制定持续优化计划

实战项目

  1. 企业级性能优化
    • 为大型 Bootstrap 应用制定性能优化方案
    • 实现自动化性能测试
    • 建立性能监控和报警系统
    • 制定性能优化的 CI/CD 流程

通过这些练习,你将能够熟练掌握 Bootstrap 应用的性能优化技术,并能够在实际项目中应用这些最佳实践。