浏览器相关 API:DOM 操作全解析

引言

DOM(文档对象模型)是Web开发的核心,它代表了HTML和XML文档的结构化表示。高效的DOM操作对于构建高性能Web应用至关重要。本文将全面解析DOM操作相关的API、性能优化策略和现代最佳实践。

一、DOM基础与性能考量

1.1 DOM操作的成本分析

DOM操作是浏览器中成本最高的操作之一,理解其性能影响是优化的第一步。

javascript 复制代码
class DOMPerformanceAnalyzer {
  // 重排(Reflow)测试
  static testReflow() {
    const container = document.createElement('div');
    document.body.appendChild(container);
    
    // 连续修改样式导致多次重排
    console.time('多次重排');
    for (let i = 0; i < 1000; i++) {
      container.style.width = i + 'px';
      container.style.height = i + 'px';
      container.style.padding = i + 'px';
    }
    console.timeEnd('多次重排');
    
    // 使用cssText批量修改
    console.time('批量修改');
    let styles = '';
    for (let i = 0; i < 1000; i++) {
      styles = `width: ${i}px; height: ${i}px; padding: ${i}px;`;
    }
    container.style.cssText = styles;
    console.timeEnd('批量修改');
    
    document.body.removeChild(container);
  }
  
  // 重绘(Repaint)优化
  static testRepaint() {
    const elements = [];
    const container = document.createElement('div');
    document.body.appendChild(container);
    
    // 创建1000个元素
    for (let i = 0; i < 1000; i++) {
      const el = document.createElement('div');
      el.textContent = 'Item ' + i;
      elements.push(el);
    }
    
    // 一次性添加到DOM
    console.time('一次性添加');
    const fragment = document.createDocumentFragment();
    elements.forEach(el => fragment.appendChild(el));
    container.appendChild(fragment);
    console.timeEnd('一次性添加');
    
    document.body.removeChild(container);
  }
}

// 性能测试
DOMPerformanceAnalyzer.testReflow();
DOMPerformanceAnalyzer.testRepaint();
1.2 选择器性能优化

不同的DOM选择方法在性能上有显著差异。

javascript 复制代码
class SelectorPerformance {
  static compareSelectors() {
    const container = document.createElement('div');
    container.id = 'test-container';
    for (let i = 0; i < 1000; i++) {
      const div = document.createElement('div');
      div.className = i % 2 === 0 ? 'even item' : 'odd item';
      div.setAttribute('data-index', i);
      container.appendChild(div);
    }
    document.body.appendChild(container);
    
    // 各种选择器的性能比较
    const selectors = [
      {
        name: 'getElementById',
        test: () => document.getElementById('test-container')
      },
      {
        name: 'querySelector',
        test: () => document.querySelector('#test-container')
      },
      {
        name: 'getElementsByClassName',
        test: () => document.getElementsByClassName('even')
      },
      {
        name: 'querySelectorAll (class)',
        test: () => document.querySelectorAll('.even')
      },
      {
        name: 'querySelectorAll (attribute)',
        test: () => document.querySelectorAll('[data-index]')
      }
    ];
    
    selectors.forEach(selector => {
      console.time(selector.name);
      for (let i = 0; i < 1000; i++) {
        selector.test();
      }
      console.timeEnd(selector.name);
    });
    
    document.body.removeChild(container);
  }
  
  // 选择器最佳实践
  static selectorBestPractices() {
    // 1. 缓存选择器结果
    const cachedElements = {
      container: document.getElementById('container'),
      buttons: document.querySelectorAll('.btn'),
      form: document.forms['user-form']
    };
    
    // 2. 使用最具体的父元素
    const parent = document.getElementById('specific-parent');
    const children = parent.querySelectorAll('.child-element');
    
    // 3. 避免过度使用通用选择器
    // 不好: document.querySelectorAll('div .item span')
    // 好: container.querySelectorAll('.item > span')
    
    // 4. 使用ID选择器最快
    const fastest = document.getElementById('unique-id');
    
    return cachedElements;
  }
}

二、虚拟DOM实现原理

2.1 基础虚拟DOM实现
javascript 复制代码
class VNode {
  constructor(tag, props = {}, children = []) {
    this.tag = tag;
    this.props = props;
    this.children = children;
    this.key = props.key || null;
    this.el = null; // 对应的真实DOM
  }
  
  // 创建虚拟DOM
  static create(tag, props, ...children) {
    // 扁平化children数组
    const flatChildren = children.reduce((acc, child) => {
      if (Array.isArray(child)) {
        return acc.concat(child);
      } else if (child == null || child === false) {
        return acc;
      } else {
        return acc.concat(child);
      }
    }, []);
    
    // 处理文本节点
    const processedChildren = flatChildren.map(child => {
      if (typeof child === 'string' || typeof child === 'number') {
        return VNode.createText(child);
      }
      return child;
    });
    
    return new VNode(tag, props || {}, processedChildren);
  }
  
  // 创建文本节点
  static createText(text) {
    return new VNode('#text', { nodeValue: text }, []);
  }
  
  // 渲染为真实DOM
  render() {
    // 文本节点
    if (this.tag === '#text') {
      return document.createTextNode(this.props.nodeValue);
    }
    
    // 创建元素
    const el = document.createElement(this.tag);
    
    // 设置属性
    for (const [key, value] of Object.entries(this.props)) {
      if (key.startsWith('on') && typeof value === 'function') {
        // 事件处理
        const eventName = key.slice(2).toLowerCase();
        el.addEventListener(eventName, value);
      } else if (key === 'className') {
        // class属性
        el.className = value;
      } else if (key === 'style' && typeof value === 'object') {
        // style对象
        Object.assign(el.style, value);
      } else if (key !== 'key') {
        // 其他属性
        el.setAttribute(key, value);
      }
    }
    
    // 递归渲染子节点
    this.children.forEach(child => {
      if (child) {
        const childEl = child.render();
        el.appendChild(childEl);
        child.el = childEl; // 保存DOM引用
      }
    });
    
    this.el = el;
    return el;
  }
}

// 虚拟DOM使用示例
class VirtualDOMExample {
  static createVirtualDOM() {
    const vdom = VNode.create(
      'div',
      { id: 'app', className: 'container' },
      VNode.create('h1', null, 'Hello Virtual DOM'),
      VNode.create(
        'ul',
        { style: { color: 'blue', padding: '10px' } },
        VNode.create('li', { key: '1' }, 'Item 1'),
        VNode.create('li', { key: '2' }, 'Item 2'),
        VNode.create('li', { key: '3' }, 'Item 3')
      ),
      VNode.create(
        'button',
        { 
          onClick: () => alert('Clicked!'),
          className: 'btn btn-primary'
        },
        'Click Me'
      )
    );
    
    return vdom;
  }
  
  static mount(containerId) {
    const container = document.getElementById(containerId);
    const vdom = this.createVirtualDOM();
    const realDOM = vdom.render();
    container.appendChild(realDOM);
    return vdom;
  }
}
2.2 组件化虚拟DOM
javascript 复制代码
// 组件基类
class Component {
  constructor(props = {}) {
    this.props = props;
    this.state = {};
    this.vnode = null;
  }
  
  setState(partialState) {
    this.state = { ...this.state, ...partialState };
    this.update();
  }
  
  update() {
    const oldVNode = this.vnode;
    const newVNode = this.render();
    
    // 执行diff和patch
    const patches = VirtualDOM.diff(oldVNode, newVNode);
    VirtualDOM.patch(this.vnode.el.parentNode, patches);
    
    this.vnode = newVNode;
  }
  
  render() {
    throw new Error('render() must be implemented');
  }
  
  // 生命周期方法
  componentDidMount() {}
  componentDidUpdate() {}
  componentWillUnmount() {}
}

// 函数式组件支持
class FunctionalComponent extends Component {
  constructor(props, renderFn) {
    super(props);
    this.renderFn = renderFn;
  }
  
  render() {
    return this.renderFn(this.props);
  }
}

// 组件示例
class TodoList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      todos: [],
      inputValue: ''
    };
  }
  
  handleInputChange = (e) => {
    this.setState({ inputValue: e.target.value });
  };
  
  handleAddTodo = () => {
    if (this.state.inputValue.trim()) {
      this.setState({
        todos: [...this.state.todos, this.state.inputValue],
        inputValue: ''
      });
    }
  };
  
  handleRemoveTodo = (index) => {
    const newTodos = [...this.state.todos];
    newTodos.splice(index, 1);
    this.setState({ todos: newTodos });
  };
  
  render() {
    return VNode.create(
      'div',
      { className: 'todo-list' },
      VNode.create('h2', null, 'Todo List'),
      VNode.create(
        'div',
        { className: 'input-group' },
        VNode.create('input', {
          type: 'text',
          value: this.state.inputValue,
          onInput: this.handleInputChange,
          placeholder: 'Add new todo'
        }),
        VNode.create(
          'button',
          { onClick: this.handleAddTodo },
          'Add'
        )
      ),
      VNode.create(
        'ul',
        null,
        ...this.state.todos.map((todo, index) =>
          VNode.create(
            'li',
            { key: index, className: 'todo-item' },
            todo,
            VNode.create(
              'button',
              { 
                onClick: () => this.handleRemoveTodo(index),
                className: 'remove-btn'
              },
              '×'
            )
          )
        )
      )
    );
  }
}

三、DOM Diff算法深度解析

3.1 完整的Diff算法实现
javascript 复制代码
class VirtualDOM {
  // 比较两个虚拟节点的差异
  static diff(oldVNode, newVNode) {
    // 如果旧节点不存在, 直接创建新节点
    if (!oldVNode) {
      return { type: "CREATE", vnode: newVNode };
    }

    // 如果新节点不存在, 删除旧节点
    if (!newVNode) {
      return { type: "REMOVE" };
    }

    // 如果节点类型不同, 直接替换
    if (this.isDifferentType(oldVNode, newVNode)) {
      return {
        type: "REPLACE",
        oldVNode,
        newVNode,
      };
    }

    // 如果是文本节点, 比较文本内容
    if (oldVNode.tag === "#text" && newVNode.tag === "#text") {
      if (oldVNode.props.nodeValue !== newVNode.props.nodeValue) {
        return {
          type: "UPDATE_TEXT",
          oldVNode,
          newVNode,
        };
      }
      return null;
    }

    // 比较属性差异
    const propsPatches = this.diffProps(oldVNode, newVNode);

    // 比较子节点差异
    const childrenPatches = this.diffChildren(oldVNode, newVNode);

    // 如果有差异, 返回补丁
    if (propsPatches.length > 0 || childrenPatches.length > 0) {
      return {
        type: "UPDATE_ELEMENT",
        props: propsPatches,
        children: childrenPatches,
        vnode: newVNode,
      };
    }

    return null;
  }

  // 判断节点类型是否不同
  static isDifferentType(vnode1, vnode2) {
    return vnode1.tag !== vnode2.tag || vnode1.key !== vnode2.key;
  }

  // 比较属性差异
  static diffProps(oldVNode, newVNode) {
    const patches = [];
    const oldProps = oldVNode.props;
    const newProps = newVNode.props;

    // 检查新增或修改的属性
    for (const [key, newValue] of Object.entries(newProps)) {
      const oldValue = oldProps[key];

      // 事件处理函数特殊处理
      if (key.startsWith("on")) {
        if (oldValue !== newValue) {
          patches.push({
            type: "UPDATE_EVENT",
            key,
            oldValue,
            newValue,
          });
        }
        continue;
      }

      // 其他属性比较
      if (oldValue !== newValue) {
        patches.push({
          type: "UPDATE_PROP",
          key,
          value: newValue,
        });
      }
    }

    // 检查被删除的属性
    for (const key of Object.keys(oldProps)) {
      if (!(key in newProps)) {
        patches.push({
          type: "REMOVE_PROP",
          key,
        });
      }
    }

    return patches;
  }

  // 比较子节点差异(使用key优化)
  static diffChildren(oldVNode, newVNode) {
    const patches = [];
    const oldChildren = oldVNode.children;
    const newChildren = newVNode.children;

    // 使用key映射优化查找
    const oldKeyMap = new Map();
    oldChildren.forEach((child, index) => {
      if (child.key != null) {
        oldKeyMap.set(child.key, { child, index });
      }
    });

    let lastIndex = 0;
    const newChildrenPatches = [];

    // 遍历新子节点
    for (let i = 0; i < newChildren.length; i++) {
      const newChild = newChildren[i];
      const newKey = newChild.key;

      let oldChildIndex = -1;
      let oldChild = null;

      // 通过key查找旧节点
      if (newKey != null && oldKeyMap.has(newKey)) {
        const item = oldKeyMap.get(newKey);
        oldChildIndex = item.index;
        oldChild = item.child;
        oldKeyMap.delete(newKey); // 从map中移除, 后续剩下的就是需要删除的
      } else {
        // 如果没有key, 尝试通过位置查找(效率较低)
        oldChildIndex = i < oldChildren.length ? i : -1;
        oldChild = oldChildIndex !== -1 ? oldChildren[oldChildIndex] : null;

        // 检查类型是否匹配
        if (oldChild && this.isDifferentType(oldChild, newChild)) {
          oldChild = null;
          oldChildIndex = -1;
        }
      }

      // 递归比较子节点
      const childPath = this.diff(oldChild, newChild);

      if (childPath) {
        newChildrenPatches.push({
          index: i,
          oldIndex: oldChildIndex,
          patch: childPath,
        });
      }

      // 判断是否需要移动
      if (oldChildIndex !== -1) {
        if (oldChildIndex < lastIndex) {
          // 需要移动
          patches.push({
            type: "MOVE",
            fromIndex: oldChildIndex,
            toIndex: i,
          });
        }
        lastIndex = Math.max(lastIndex, oldChildIndex);
      }
    }

    // 处理需要删除的旧节点
    for (const { child, index } of oldKeyMap.values()) {
      patches.push({
        type: "REMOVE_CHILD",
        index,
      });
    }

    // 添加子节点补丁
    patches.push(...newChildrenPatches);

    return patches;
  }

  // 应用补丁到真实DOM
  static patch(parent, patches) {
    if (!patches) return;

    switch (patches.type) {
      case "CREATE":
        const newEl = patches.vnode.render();
        parent.appendChild(newEl);
        patches.vnode.el = newEl;
        break;

      case "REMOVE":
        if (parent.parentNode) {
          parent.parentNode.removeChild(parent);
        }
        break;

      case "REPLACE":
        const oldEl = patches.oldVNode.el;
        const newEl2 = patches.newVNode.render();
        oldEl.parentNode.replaceChild(newEl2, oldEl);
        patches.newVNode.el = newEl2;
        break;

      case "UPDATE_TEXT":
        patches.oldVNode.textContent = patches.newVNode.props.nodeValue;
        patches.newVNode.el = patches.oldVNode.el;
        break;

      case "UPDATE_ELEMENT":
        this.patchElement(patches.oldVNode.el, patches);
        patches.vnode.el = patches.oldVNode.el;
        break;
    }
  }

  // 应用元素级别的补丁
  static patchElement(el, patches) {
    // 应用属性补丁
    if (patches.props) {
      patches.props.forEach((patch) => {
        switch (path.type) {
          case "UPDATE_PROP":
            if (patch.key === "className") {
              el.className = patch.value;
            } else if (
              patch.key === "style" &&
              typeof patch.value === "object"
            ) {
              Object.assign(el.style, patch.value);
            } else {
              el.setAttribute(patch.key, patch.value);
            }
            break;
          case "REMOVE_PROP":
            el.removeAttribute(patch.key);
            break;
          case "UPDATE_EVENT":
            const eventName = patch.key.slice(2).toLowetCase();
            if (patch.oldValue) {
              el.removeEventListener(eventName, patch.oldValue);
            }
            if (patch.newValue) {
              el.addEventListener(eventName, patch.newValue);
            }
            break;
        }
      });
    }

    // 应用子节点补丁
    if (patches.children) {
      this.patchChildren(el, patches.children);
    }
  }

  // 应用子节点补丁
  static patchChildren(parent, patches) {
    const childNodes = Array.from(parent.childNodes);

    patches.forEach((patch) => {
      switch (patch.type) {
        case "MOVE":
          const childToMove = childNodes[patch.fromIndex];
          const referenceNode = childNodes[patch.toIndex] || null;
          parent.insertBefore(childToMove, referenceNode);
          break;

        case "REMOVE_CHILD":
          const childToRemove = childNodes[patch.index];
          if (childToRemove) {
            parent.removeChild(childToRemove);
          }
          break;
        default:
          if (patch.patch) {
            const childEl =
              childNodes[patch.oldIndex] || parent.childNodes[patch.index];
            if (childEl) {
              this.patch(childEl, patch.patch);
            } else if (patch.patch.type === "CREATE") {
              const newEl = patch.patch.vnode.render();
              const referenceNode = parent.childNodes[patch.index] || null;
              parent.insertBefore(newEl, referenceNode);
            }
          }
          break;
      }
    });
  }
}
3.2 Diff算法优化策略
javascript 复制代码
class OptimizedDiff {
  // 双指针算法优化
  static optimizedDiff(oldChilren, newChildren) {
    let oldStartIdx = 0;
    let oldEndIdx = oldChilren.length - 1;
    let newStartIdx = 0;
    let newEndIdx = newChildren.length - 1;

    let oldStartVNode = oldChilren[oldStartIdx];
    let oldEndVNode = oldChilren[oldEndIdx];
    let newStartVNode = newChildren[newStartIdx];
    let newEndVNode = newChildren[newEndIdx];

    const patches = [];
    const oldKeyToIdx = this.createKeyMap(oldChilren);

    while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
      // 跳过已处理的节点
      if (!oldStartVNode) {
        oldStartVNode = oldChilren[++oldStartIdx];
        continue;
      }
      if (!oldEndVNode) {
        oldEndVNode = oldChilren[--oldEndIdx];
        continue;
      }

      // 四种比较情况
      if (this.sameVNode(oldStartVNode, newStartVNode)) {
        // 情况1: 头头比较
        patches.push({
          type: "UPDATE",
          oldIdx: oldStartIdx,
          newIdx: newStartIdx,
        });
        oldStartVNode = oldChilren[++oldStartIdx];
        newStartVNode = newChildren[++newStartIdx];
      } else if (this.sameVNode(oldEndVNode, newEndVNode)) {
        // 情况2: 尾尾比较
        patches.push({
          type: "UPDATE",
          oldIdx: oldEndIdx,
          newIdx: newEndIdx,
        });
        oldEndVNode = oldChilren[--oldEndIdx];
        newEndVNode = newChildren[--newEndIdx];
      } else if (this.sameVNode(oldStartVNode, newEndVNode)) {
        // 情况3: 头尾比较(需要移动)
        patches.push({
          type: "MOVE",
          fromIdx: oldStartIdx,
          toIdx: oldEndIdx,
        });
        oldStartVNode = oldChilren[++oldStartIdx];
        newEndVNode = newChildren[--newEndIdx];
      } else if (this.sameVNode(oldEndVNode, newStartVNode)) {
        // 情况4: 头尾比较(需要移动)
        patches.push({
          type: "MOVE",
          fromIdx: oldEndIdx,
          toIdx: oldStartIdx,
        });
        oldEndVNode = oldChilren[--oldEndIdx];
        newStartVNode = newChildren[++newStartIdx];
      } else {
        // 情况5: 通过key查找
        const idxInOld = oldKeyToIdx.get(newStartVNode.key);

        if (idxInOld == null) {
          // 新节点, 需要创建
          patches.push({
            type: "CREATE",
            vnode: newStartVNode,
            idx: newStartIdx,
          });
        } else {
          // 找到对应节点, 需要移动
          const vnodeToMove = oldChilren[idxInOld];
          patches.push({
            type: "MOVE",
            fromIdx: idxInOld,
            toIdx: newStartIdx,
          });
          // 标记为已处理
          oldChilren[idxInOld] = undefined;
        }

        newStartVNode = newChildren[++newStartIdx];
      }
    }

    // 处理剩余节点
    if (oldStartIdx > oldEndIdx) {
      // 添加新节点
      for (let i = newStartIdx; i <= newEndIdx; i++) {
        patches.push({
          type: "CREATE",
          vnode: newChildren[i],
          idx: i,
        });
      }
    } else if (newStartIdx > newEndIdx) {
      // 删除旧节点
      for (let i = oldStartIdx; i <= oldEndIdx; i++) {
        if (oldChilren[i]) {
          patches.push({
            type: "REMOVE",
            idx: i,
          });
        }
      }
    }

    return patches;
  }

  static createKeyMap(children) {
    const map = new Map();
    children.forEach((child, idx) => {
      if (child && child.key !== null) {
        map.set(child.key, idx);
      }
    });
    return map;
  }

  static sameVNode(vnode1, vnode2) {
    return (
      vnode1 && vnode2 && vnode1.tag === vnode2.tag && vnode1.key === vnode2.key
    );
  }

  // 事件切片优化
  static timeSlicedDiff(oldVNode, newVNode, callback, chunkSize = 10) {
    const patches = [];
    const queue = [{ oldVNode, newVNode, path: [] }];

    function processChunk() {
      const startTime = performance.now();
      let processed = 0;

      while (queue.length > 0 && processed < chunkSize) {
        const { oldVNode, newVNode, path } = queue.shift();
        const patch = VirtualDOM.diff(oldVNode, newVNode);

        if (patch) {
          patches.push({ patch, path });
        }

        // 添加子节点到队列
        if (oldVNode && newVNode && oldVNode.children && newVNode.children) {
          const maxLen = Math.max(
            oldVNode.children.length,
            newVNode.children.length
          );
          for (let i = 0; i < maxLen; i++) {
            queue.push({
              oldVNode: oldVNode.children[i],
              newVNode: newVNode.children[i],
              path: [...path, i],
            });
          }
        }

        processed++;

        // 检查是否超过时间限制
        if (performance.now() - startTime > 16) {
          // 约一帧的时间
          break;
        }
      }

      if (queue.length > 0) {
        // 继续处理下一个chunk
        requestIdleCallback(processChunk);
      } else {
        // 完成,执行回调
        callback(patches);
      }
    }

    // 开始处理
    requestIdleCallback(processChunk);
  }
}

四、事件委托高级模式

4.1 完善的事件委托系统
javascript 复制代码
class EventDelegation {
  constructor(rootElement = document) {
    this.root = rootElement;
    this.handlers = new Map(); // Map<eventType, Map<selector, handler>>
    this.eventListeners = new Map(); // Map<eventType, listener>
  }
  
  // 注册事件委托
  on(eventType, selector, handler, options = {}) {
    if (!this.handlers.has(eventType)) {
      this.handlers.set(eventType, new Map());
      
      // 为每种事件类型添加一个事件监听器
      const listener = (event) => {
        this.handleEvent(eventType, event);
      };
      
      this.root.addEventListener(eventType, listener, options);
      this.eventListeners.set(eventType, listener);
    }
    
    const selectorMap = this.handlers.get(eventType);
    selectorMap.set(selector, handler);
  }
  
  // 移除事件委托
  off(eventType, selector) {
    const selectorMap = this.handlers.get(eventType);
    if (selectorMap) {
      selectorMap.delete(selector);
      
      // 如果没有其他选择器,移除事件监听器
      if (selectorMap.size === 0) {
        const listener = this.eventListeners.get(eventType);
        if (listener) {
          this.root.removeEventListener(eventType, listener);
          this.eventListeners.delete(eventType);
        }
        this.handlers.delete(eventType);
      }
    }
  }
  
  // 处理事件
  handleEvent(eventType, event) {
    const selectorMap = this.handlers.get(eventType);
    if (!selectorMap) return;
    
    // 从目标元素向上查找匹配的选择器
    let element = event.target;
    
    while (element && element !== this.root) {
      // 检查所有选择器
      for (const [selector, handler] of selectorMap.entries()) {
        if (element.matches(selector)) {
          // 执行处理器
          const result = handler.call(element, event);
          
          // 如果处理器返回false,阻止默认行为和冒泡
          if (result === false) {
            event.preventDefault();
            event.stopPropagation();
          }
          
          // 如果处理器返回true,继续检查父元素
          if (result !== true) {
            return;
          }
        }
      }
      
      element = element.parentElement;
    }
  }
  
  // 一次性事件
  once(eventType, selector, handler) {
    const onceHandler = (event) => {
      const result = handler.call(event.target, event);
      this.off(eventType, selector, onceHandler);
      return result;
    };
    
    this.on(eventType, selector, onceHandler);
  }
  
  // 动态添加支持
  static createDynamicDelegation() {
    const delegation = new EventDelegation();
    
    // 监听DOM变化,自动处理新元素
    const observer = new MutationObserver((mutations) => {
      for (const mutation of mutations) {
        if (mutation.type === 'childList') {
          mutation.addedNodes.forEach(node => {
            if (node.nodeType === Node.ELEMENT_NODE) {
              delegation.bindNewElement(node);
            }
          });
        }
      }
    });
    
    observer.observe(document.body, {
      childList: true,
      subtree: true
    });
    
    return delegation;
  }
  
  // 绑定新元素
  bindNewElement(element) {
    // 为元素绑定已注册的事件
    for (const [eventType, selectorMap] of this.handlers.entries()) {
      for (const [selector, handler] of selectorMap.entries()) {
        if (element.matches(selector)) {
          element.addEventListener(eventType, handler);
        }
      }
    }
    
    // 递归处理子元素
    element.querySelectorAll('*').forEach(child => {
      this.bindNewElement(child);
    });
  }
  
  // 事件节流委托
  onThrottled(eventType, selector, handler, delay = 100) {
    let lastCall = 0;
    let timeoutId = null;
    
    const throttledHandler = (event) => {
      const now = Date.now();
      const timeSinceLastCall = now - lastCall;
      
      if (timeSinceLastCall >= delay) {
        lastCall = now;
        handler.call(event.target, event);
      } else {
        // 取消之前的超时
        if (timeoutId) {
          clearTimeout(timeoutId);
        }
        
        // 设置新的超时
        timeoutId = setTimeout(() => {
          lastCall = Date.now();
          handler.call(event.target, event);
        }, delay - timeSinceLastCall);
      }
    };
    
    this.on(eventType, selector, throttledHandler);
  }
  
  // 事件防抖委托
  onDebounced(eventType, selector, handler, delay = 100) {
    let timeoutId = null;
    
    const debouncedHandler = (event) => {
      if (timeoutId) {
        clearTimeout(timeoutId);
      }
      
      timeoutId = setTimeout(() => {
        handler.call(event.target, event);
        timeoutId = null;
      }, delay);
    };
    
    this.on(eventType, selector, debouncedHandler);
  }
}

// 使用示例
class EventDelegationExample {
  static setupDelegation() {
    const delegation = new EventDelegation(document.body);
    
    // 为所有按钮添加点击事件
    delegation.on('click', '.btn', function(event) {
      console.log('Button clicked:', this.textContent);
    });
    
    // 为动态添加的列表项添加事件
    delegation.on('click', '.list-item', function(event) {
      console.log('List item clicked:', this.dataset.id);
    });
    
    // 表单提交防抖
    delegation.onDebounced('input', '.search-input', function(event) {
      console.log('Search:', this.value);
    }, 300);
    
    // 滚动事件节流
    delegation.onThrottled('scroll', '.scroll-container', function(event) {
      console.log('Scrolling...');
    }, 100);
    
    // 一次性事件
    delegation.once('click', '.intro-modal .close', function(event) {
      this.parentElement.style.display = 'none';
    });
    
    return delegation;
  }
}
4.2 触摸事件委托
javascript 复制代码
class TouchEventDelegation extends EventDelegation {
  constructor(rootElement = document) {
    super(rootElement);
    this.touchState = new Map(); // Map<touchId, {element, startX, startY}>
    
    // 初始化触摸事件
    this.initTouchEvents();
  }
  
  initTouchEvents() {
    // 处理触摸开始
    this.on('touchstart', '*', (event) => {
      for (const touch of event.changedTouches) {
        this.touchState.set(touch.identifier, {
          element: event.target,
          startX: touch.clientX,
          startY: touch.clientY,
          startTime: Date.now()
        });
      }
    }, { passive: true });
    
    // 处理触摸移动
    this.on('touchmove', '*', (event) => {
      for (const touch of event.changedTouches) {
        const state = this.touchState.get(touch.identifier);
        if (state) {
          const deltaX = touch.clientX - state.startX;
          const deltaY = touch.clientY - state.startY;
          
          // 触发自定义事件
          const customEvent = new CustomEvent('touchdrag', {
            detail: {
              touchId: touch.identifier,
              element: state.element,
              deltaX,
              deltaY,
              clientX: touch.clientX,
              clientY: touch.clientY
            },
            bubbles: true
          });
          
          state.element.dispatchEvent(customEvent);
        }
      }
    }, { passive: true });
    
    // 处理触摸结束
    this.on('touchend', '*', (event) => {
      for (const touch of event.changedTouches) {
        const state = this.touchState.get(touch.identifier);
        if (state) {
          const deltaTime = Date.now() - state.startTime;
          const deltaX = touch.clientX - state.startX;
          const deltaY = touch.clientY - state.startY;
          const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
          
          // 判断是否是点击(快速触摸且移动距离小)
          if (deltaTime < 300 && distance < 10) {
            const clickEvent = new MouseEvent('click', {
              bubbles: true,
              cancelable: true,
              clientX: touch.clientX,
              clientY: touch.clientY
            });
            
            state.element.dispatchEvent(clickEvent);
          }
          
          this.touchState.delete(touch.identifier);
        }
      }
    }, { passive: true });
  }
  
  // 添加滑动手势支持
  enableSwipe(selector, options = {}) {
    const defaultOptions = {
      threshold: 50, // 最小滑动距离
      velocity: 0.3, // 最小速度
      direction: 'horizontal' // horizontal, vertical, both
    };
    
    const config = { ...defaultOptions, ...options };
    
    this.on('touchdrag', selector, (event) => {
      const { deltaX, deltaY, element } = event.detail;
      
      // 检查滑动方向
      const isHorizontal = Math.abs(deltaX) > Math.abs(deltaY);
      const isValidDirection = 
        config.direction === 'both' ||
        (config.direction === 'horizontal' && isHorizontal) ||
        (config.direction === 'vertical' && !isHorizontal);
      
      if (!isValidDirection) return;
      
      // 检查滑动距离
      const distance = isHorizontal ? Math.abs(deltaX) : Math.abs(deltaY);
      if (distance < config.threshold) return;
      
      // 确定滑动方向
      let direction = '';
      if (isHorizontal) {
        direction = deltaX > 0 ? 'right' : 'left';
      } else {
        direction = deltaY > 0 ? 'down' : 'up';
      }
      
      // 触发滑动手势事件
      const swipeEvent = new CustomEvent('swipe', {
        detail: {
          direction,
          distance,
          element,
          deltaX,
          deltaY
        },
        bubbles: true
      });
      
      element.dispatchEvent(swipeEvent);
    });
  }
}

五、自定义事件系统

5.1 高级事件总线
javascript 复制代码
class EventEmitter {
  constructor() {
    this.events = new Map();
    this.onceEvents = new Map();
    this.maxListeners = 10;
    this.wildcard = false;
  }
  
  // 添加事件监听器
  on(eventName, listener) {
    if (!this.events.has(eventName)) {
      this.events.set(eventName, []);
    }
    
    const listeners = this.events.get(eventName);
    listeners.push(listener);
    
    // 检查监听器数量限制
    if (listeners.length > this.maxListeners) {
      console.warn(`Event "${eventName}" has more than ${this.maxListeners} listeners`);
    }
    
    return this;
  }
  
  // 一次性事件监听器
  once(eventName, listener) {
    const onceWrapper = (...args) => {
      listener.apply(this, args);
      this.off(eventName, onceWrapper);
    };
    
    // 保存原始监听器引用,以便可以正确移除
    onceWrapper.listener = listener;
    
    if (!this.onceEvents.has(eventName)) {
      this.onceEvents.set(eventName, new Map());
    }
    
    this.onceEvents.get(eventName).set(listener, onceWrapper);
    return this.on(eventName, onceWrapper);
  }
  
  // 移除事件监听器
  off(eventName, listener) {
    if (!this.events.has(eventName)) return this;
    
    const listeners = this.events.get(eventName);
    
    // 移除特定监听器
    if (listener) {
      const index = listeners.indexOf(listener);
      if (index !== -1) {
        listeners.splice(index, 1);
      }
      
      // 同时移除once包装器
      if (this.onceEvents.has(eventName)) {
        const onceMap = this.onceEvents.get(eventName);
        if (onceMap.has(listener)) {
          const onceWrapper = onceMap.get(listener);
          const wrapperIndex = listeners.indexOf(onceWrapper);
          if (wrapperIndex !== -1) {
            listeners.splice(wrapperIndex, 1);
          }
          onceMap.delete(listener);
        }
      }
    } else {
      // 移除所有监听器
      listeners.length = 0;
      if (this.onceEvents.has(eventName)) {
        this.onceEvents.get(eventName).clear();
      }
    }
    
    // 如果监听器数组为空,删除事件
    if (listeners.length === 0) {
      this.events.delete(eventName);
      this.onceEvents.delete(eventName);
    }
    
    return this;
  }
  
  // 触发事件
  emit(eventName, ...args) {
    // 触发精确匹配的事件
    if (this.events.has(eventName)) {
      const listeners = this.events.get(eventName).slice();
      
      // 异步触发
      Promise.resolve().then(() => {
        listeners.forEach(listener => {
          try {
            listener.apply(this, args);
          } catch (error) {
            console.error(`Error in event listener for "${eventName}":`, error);
          }
        });
      });
    }
    
    // 触发通配符事件
    if (this.wildcard) {
      this.emit('*', eventName, ...args);
    }
    
    // 触发命名空间事件
    const namespaceIndex = eventName.indexOf(':');
    if (namespaceIndex !== -1) {
      const namespace = eventName.substring(0, namespaceIndex + 1);
      const eventWithoutNamespace = eventName.substring(namespaceIndex + 1);
      
      if (this.events.has(namespace)) {
        const listeners = this.events.get(namespace).slice();
        
        Promise.resolve().then(() => {
          listeners.forEach(listener => {
            try {
              listener.call(this, eventWithoutNamespace, ...args);
            } catch (error) {
              console.error(`Error in namespace event listener for "${namespace}":`, error);
            }
          });
        });
      }
    }
    
    return this;
  }
  
  // 获取事件监听器数量
  listenerCount(eventName) {
    if (!this.events.has(eventName)) return 0;
    return this.events.get(eventName).length;
  }
  
  // 获取所有事件名称
  eventNames() {
    return Array.from(this.events.keys());
  }
  
  // 设置最大监听器数量
  setMaxListeners(n) {
    this.maxListeners = n;
    return this;
  }
  
  // 启用通配符监听
  enableWildcard() {
    this.wildcard = true;
    return this;
  }
  
  // 链式操作支持
  chain(eventName) {
    return {
      on: (listener) => {
        this.on(eventName, listener);
        return this;
      },
      once: (listener) => {
        this.once(eventName, listener);
        return this;
      },
      off: (listener) => {
        this.off(eventName, listener);
        return this;
      },
      emit: (...args) => {
        this.emit(eventName, ...args);
        return this;
      }
    };
  }
}

// 异步事件系统
class AsyncEventEmitter extends EventEmitter {
  constructor() {
    super();
    this.asyncListeners = new Map();
  }
  
  // 添加异步事件监听器
  onAsync(eventName, listener) {
    if (!this.asyncListeners.has(eventName)) {
      this.asyncListeners.set(eventName, []);
    }
    
    this.asyncListeners.get(eventName).push(listener);
    return this;
  }
  
  // 异步触发事件
  async emitAsync(eventName, ...args) {
    const promises = [];
    
    // 同步监听器
    if (this.events.has(eventName)) {
      this.events.get(eventName).forEach(listener => {
        try {
          const result = listener.apply(this, args);
          if (result instanceof Promise) {
            promises.push(result);
          }
        } catch (error) {
          console.error(`Error in sync event listener for "${eventName}":`, error);
        }
      });
    }
    
    // 异步监听器
    if (this.asyncListeners.has(eventName)) {
      this.asyncListeners.get(eventName).forEach(async listener => {
        try {
          const result = await listener.apply(this, args);
          if (result instanceof Promise) {
            promises.push(result);
          }
        } catch (error) {
          console.error(`Error in async event listener for "${eventName}":`, error);
        }
      });
    }
    
    // 等待所有异步操作完成
    return Promise.all(promises);
  }
  
  // 带有超时的事件触发
  async emitWithTimeout(eventName, timeout, ...args) {
    const timeoutPromise = new Promise((_, reject) => {
      setTimeout(() => reject(new Error(`Event "${eventName}" timeout after ${timeout}ms`)), timeout);
    });
    
    const eventPromise = this.emitAsync(eventName, ...args);
    
    return Promise.race([eventPromise, timeoutPromise]);
  }
}

// 使用示例
class EventSystemExample {
  static createEventSystem() {
    const emitter = new AsyncEventEmitter();
    
    // 启用通配符
    emitter.enableWildcard();
    
    // 监听所有事件
    emitter.on('*', (eventName, ...args) => {
      console.log(`Event "${eventName}" emitted with args:`, args);
    });
    
    // 异步事件处理
    emitter.onAsync('user:login', async (userData) => {
      console.log('User login event received:', userData);
      // 模拟异步操作
      await new Promise(resolve => setTimeout(resolve, 1000));
      console.log('Login processing completed');
      return { success: true };
    });
    
    // 带超时的事件触发
    emitter.emitWithTimeout('user:login', 2000, { userId: 123, username: 'john' })
      .then(result => console.log('Login successful:', result))
      .catch(error => console.error('Login failed:', error));
    
    // 链式调用
    emitter.chain('app:start')
      .on(() => console.log('App starting...'))
      .emit();
    
    return emitter;
  }
}
5.2 浏览器原生事件扩展
javascript 复制代码
class NativeEventExtension {
  // 扩展EventTarget原型
  static extendEventTarget() {
    const originalAddEventListener = EventTarget.prototype.addEventListener;
    const originalRemoveEventListener = EventTarget.prototype.removeEventListener;
    const originalDispatchEvent = EventTarget.prototype.dispatchEvent;
    
    // 增强addEventListener
    EventTarget.prototype.addEventListener = function(type, listener, options) {
      // 支持once选项
      if (options && options.once) {
        const originalListener = listener;
        listener = function(...args) {
          originalListener.apply(this, args);
          this.removeEventListener(type, listener, options);
        };
      }
      
      // 支持signal选项
      if (options && options.signal) {
        const abortListener = () => {
          this.removeEventListener(type, listener, options);
        };
        options.signal.addEventListener('abort', abortListener);
        
        // 修改listener以清理signal监听器
        const originalListener = listener;
        listener = function(...args) {
          options.signal.removeEventListener('abort', abortListener);
          return originalListener.apply(this, args);
        };
      }
      
      return originalAddEventListener.call(this, type, listener, options);
    };
    
    // 保持removeEventListener不变
    EventTarget.prototype.removeEventListener = originalRemoveEventListener;
    
    // 增强dispatchEvent
    EventTarget.prototype.dispatchEvent = function(event) {
      // 支持异步事件处理
      if (event.async) {
        Promise.resolve().then(() => {
          originalDispatchEvent.call(this, event);
        });
        return true;
      }
      
      return originalDispatchEvent.call(this, event);
    };
    
    // 添加自定义方法
    EventTarget.prototype.on = function(type, listener, options) {
      this.addEventListener(type, listener, options);
      return this;
    };
    
    EventTarget.prototype.off = function(type, listener, options) {
      this.removeEventListener(type, listener, options);
      return this;
    };
    
    EventTarget.prototype.emit = function(type, detail) {
      const event = new CustomEvent(type, { detail });
      return this.dispatchEvent(event);
    };
    
    EventTarget.prototype.once = function(type, listener) {
      this.addEventListener(type, listener, { once: true });
      return this;
    };
  }
  
  // 创建可取消的延迟事件
  static createDelayedEvent(target, type, delay, detail) {
    let timeoutId = null;
    let cancelled = false;
    
    const dispatch = () => {
      if (!cancelled) {
        target.dispatchEvent(new CustomEvent(type, { detail }));
      }
    };
    
    timeoutId = setTimeout(dispatch, delay);
    
    return {
      cancel: () => {
        cancelled = true;
        if (timeoutId) {
          clearTimeout(timeoutId);
        }
      },
      dispatchNow: () => {
        if (!cancelled) {
          dispatch();
          if (timeoutId) {
            clearTimeout(timeoutId);
          }
        }
      }
    };
  }
  
  // 事件节流装饰器
  static throttleEvent(type, delay) {
    return (target, propertyKey, descriptor) => {
      const originalMethod = descriptor.value;
      let lastCall = 0;
      let timeoutId = null;
      
      descriptor.value = function(event) {
        const now = Date.now();
        
        if (now - lastCall >= delay) {
          lastCall = now;
          originalMethod.call(this, event);
        } else if (!timeoutId) {
          timeoutId = setTimeout(() => {
            lastCall = Date.now();
            originalMethod.call(this, event);
            timeoutId = null;
          }, delay - (now - lastCall));
        }
      };
      
      return descriptor;
    };
  }
  
  // 事件防抖装饰器
  static debounceEvent(type, delay) {
    return (target, propertyKey, descriptor) => {
      const originalMethod = descriptor.value;
      let timeoutId = null;
      
      descriptor.value = function(event) {
        if (timeoutId) {
          clearTimeout(timeoutId);
        }
        
        timeoutId = setTimeout(() => {
          originalMethod.call(this, event);
          timeoutId = null;
        }, delay);
      };
      
      return descriptor;
    };
  }
}

// 使用示例
class NativeEventExample {
  static setupEnhancedEvents() {
    // 扩展原生事件系统
    NativeEventExtension.extendEventTarget();
    
    const button = document.createElement('button');
    button.textContent = 'Click me';
    
    // 使用新API
    button
      .on('click', () => console.log('Clicked!'))
      .once('mouseenter', () => console.log('Mouse entered (once)'))
      .emit('custom', { message: 'Hello' });
    
    // 使用装饰器
    class Component {
      @NativeEventExtension.throttleEvent('scroll', 100)
      handleScroll(event) {
        console.log('Throttled scroll:', event);
      }
      
      @NativeEventExtension.debounceEvent('input', 300)
      handleInput(event) {
        console.log('Debounced input:', event.target.value);
      }
    }
    
    return button;
  }
}

六、DOM操作性能优化

6.1 批量DOM更新
javascript 复制代码
class BatchDOMUpdater {
  constructor() {
    this.updates = new Map(); // Map<element, {properties, children}>
    this.rafId = null;
    this.batchSize = 50; // 每批处理的最大元素数量
  }
  
  // 计划更新
  scheduleUpdate(element, updates) {
    if (!this.updates.has(element)) {
      this.updates.set(element, {
        properties: new Map(),
        children: null
      });
    }
    
    const elementUpdates = this.updates.get(element);
    
    // 合并属性更新
    if (updates.properties) {
      Object.entries(updates.properties).forEach(([key, value]) => {
        elementUpdates.properties.set(key, value);
      });
    }
    
    // 设置子节点更新
    if (updates.children !== undefined) {
      elementUpdates.children = updates.children;
    }
    
    // 请求动画帧进行批量更新
    if (!this.rafId) {
      this.rafId = requestAnimationFrame(() => this.processBatch());
    }
  }
  
  // 处理批量更新
  processBatch() {
    this.rafId = null;
    
    // 创建文档片段用于批量插入
    const fragment = document.createDocumentFragment();
    const elementsToUpdate = Array.from(this.updates.entries());
    const batch = elementsToUpdate.slice(0, this.batchSize);
    
    // 应用样式和属性更新
    batch.forEach(([element, updates]) => {
      // 批量应用样式
      if (updates.properties.size > 0) {
        const styleUpdates = {};
        const otherUpdates = {};
        
        updates.properties.forEach((value, key) => {
          if (key === 'style' && typeof value === 'object') {
            Object.assign(element.style, value);
          } else if (key.startsWith('style.')) {
            const styleProp = key.slice(6);
            element.style[styleProp] = value;
          } else if (key === 'className') {
            element.className = value;
          } else {
            otherUpdates[key] = value;
          }
        });
        
        // 一次性设置其他属性
        Object.keys(otherUpdates).forEach(key => {
          element.setAttribute(key, otherUpdates[key]);
        });
      }
      
      // 处理子节点更新
      if (updates.children !== null) {
        // 清除现有子节点
        while (element.firstChild) {
          element.removeChild(element.firstChild);
        }
        
        // 添加新子节点
        if (Array.isArray(updates.children)) {
          updates.children.forEach(child => {
            if (child instanceof Node) {
              element.appendChild(child);
            } else if (typeof child === 'string') {
              element.appendChild(document.createTextNode(child));
            }
          });
        }
      }
    });
    
    // 移除已处理的更新
    batch.forEach(([element]) => {
      this.updates.delete(element);
    });
    
    // 如果还有剩余更新,继续处理
    if (this.updates.size > 0) {
      this.rafId = requestAnimationFrame(() => this.processBatch());
    }
  }
  
  // 取消所有计划中的更新
  cancel() {
    if (this.rafId) {
      cancelAnimationFrame(this.rafId);
      this.rafId = null;
    }
    this.updates.clear();
  }
  
  // 静态方法:快速批量创建元素
  static createElements(tagName, count, properties = {}) {
    const fragment = document.createDocumentFragment();
    
    for (let i = 0; i < count; i++) {
      const element = document.createElement(tagName);
      
      // 应用属性
      Object.entries(properties).forEach(([key, value]) => {
        if (key === 'style' && typeof value === 'object') {
          Object.assign(element.style, value);
        } else if (key === 'className') {
          element.className = value;
        } else if (key.startsWith('data-')) {
          element.setAttribute(key, value);
        } else {
          element[key] = value;
        }
      });
      
      fragment.appendChild(element);
    }
    
    return fragment;
  }
  
  // 静态方法:使用模板克隆
  static cloneFromTemplate(templateId, count, data = []) {
    const template = document.getElementById(templateId);
    if (!template || template.tagName !== 'TEMPLATE') {
      throw new Error('Template not found');
    }
    
    const fragment = document.createDocumentFragment();
    
    for (let i = 0; i < count; i++) {
      const clone = document.importNode(template.content, true);
      
      // 填充数据
      if (data[i]) {
        this.fillTemplate(clone, data[i]);
      }
      
      fragment.appendChild(clone);
    }
    
    return fragment;
  }
  
  static fillTemplate(node, data) {
    // 处理文本节点
    if (node.nodeType === Node.TEXT_NODE) {
      const text = node.textContent;
      const filledText = text.replace(/\{\{(\w+)\}\}/g, (match, key) => {
        return data[key] || match;
      });
      
      if (filledText !== text) {
        node.textContent = filledText;
      }
    }
    
    // 处理元素节点
    if (node.nodeType === Node.ELEMENT_NODE) {
      // 填充属性
      Array.from(node.attributes).forEach(attr => {
        const value = attr.value;
        const filledValue = value.replace(/\{\{(\w+)\}\}/g, (match, key) => {
          return data[key] || match;
        });
        
        if (filledValue !== value) {
          node.setAttribute(attr.name, filledValue);
        }
      });
      
      // 递归处理子节点
      Array.from(node.childNodes).forEach(child => {
        this.fillTemplate(child, data);
      });
    }
  }
}
6.2 使用MutationObserver监控DOM变化
javascript 复制代码
class DOMChangeMonitor {
  constructor(options = {}) {
    this.options = {
      childList: true,
      subtree: true,
      attributes: true,
      attributeOldValue: true,
      characterData: true,
      characterDataOldValue: true,
      ...options
    };
    
    this.observer = new MutationObserver(this.handleMutations.bind(this));
    this.callbacks = {
      added: new Set(),
      removed: new Set(),
      attributeChanged: new Set(),
      textChanged: new Set()
    };
    
    this.isObserving = false;
  }
  
  // 开始监控
  observe(target = document.documentElement) {
    if (this.isObserving) {
      this.disconnect();
    }
    
    this.observer.observe(target, this.options);
    this.isObserving = true;
    return this;
  }
  
  // 停止监控
  disconnect() {
    this.observer.disconnect();
    this.isObserving = false;
    return this;
  }
  
  // 处理变化
  handleMutations(mutations) {
    mutations.forEach(mutation => {
      switch (mutation.type) {
        case 'childList':
          this.handleChildListMutation(mutation);
          break;
        case 'attributes':
          this.handleAttributeMutation(mutation);
          break;
        case 'characterData':
          this.handleCharacterDataMutation(mutation);
          break;
      }
    });
  }
  
  // 处理子节点变化
  handleChildListMutation(mutation) {
    // 新增节点
    mutation.addedNodes.forEach(node => {
      this.callbacks.added.forEach(callback => {
        callback(node, mutation.target);
      });
    });
    
    // 移除节点
    mutation.removedNodes.forEach(node => {
      this.callbacks.removed.forEach(callback => {
        callback(node, mutation.target);
      });
    });
  }
  
  // 处理属性变化
  handleAttributeMutation(mutation) {
    this.callbacks.attributeChanged.forEach(callback => {
      callback({
        target: mutation.target,
        attributeName: mutation.attributeName,
        oldValue: mutation.oldValue,
        newValue: mutation.target.getAttribute(mutation.attributeName)
      });
    });
  }
  
  // 处理文本变化
  handleCharacterDataMutation(mutation) {
    this.callbacks.textChanged.forEach(callback => {
      callback({
        target: mutation.target,
        oldValue: mutation.oldValue,
        newValue: mutation.target.textContent
      });
    });
  }
  
  // 注册回调
  on(event, callback) {
    if (this.callbacks[event]) {
      this.callbacks[event].add(callback);
    }
    return this;
  }
  
  off(event, callback) {
    if (this.callbacks[event]) {
      this.callbacks[event].delete(callback);
    }
    return this;
  }
  
  // 一次性监控
  once(event, callback) {
    const wrapper = (...args) => {
      callback(...args);
      this.off(event, wrapper);
    };
    
    this.on(event, wrapper);
    return this;
  }
  
  // 获取快照
  takeSnapshot(target = document.documentElement) {
    const snapshot = {
      timestamp: Date.now(),
      html: target.outerHTML,
      children: Array.from(target.children).map(child => ({
        tagName: child.tagName,
        attributes: Array.from(child.attributes).reduce((acc, attr) => {
          acc[attr.name] = attr.value;
          return acc;
        }, {}),
        childrenCount: child.children.length
      }))
    };
    
    return snapshot;
  }
  
  // 比较快照
  static compareSnapshots(snapshot1, snapshot2) {
    const differences = [];
    
    // 比较HTML
    if (snapshot1.html !== snapshot2.html) {
      differences.push({
        type: 'html',
        before: snapshot1.html,
        after: snapshot2.html
      });
    }
    
    // 比较子节点数量
    if (snapshot1.children.length !== snapshot2.children.length) {
      differences.push({
        type: 'childrenCount',
        before: snapshot1.children.length,
        after: snapshot2.children.length
      });
    }
    
    // 比较子节点属性
    const maxLength = Math.max(snapshot1.children.length, snapshot2.children.length);
    for (let i = 0; i < maxLength; i++) {
      const child1 = snapshot1.children[i];
      const child2 = snapshot2.children[i];
      
      if (!child1 && child2) {
        differences.push({
          type: 'childAdded',
          index: i,
          child: child2
        });
      } else if (child1 && !child2) {
        differences.push({
          type: 'childRemoved',
          index: i,
          child: child1
        });
      } else if (child1 && child2) {
        // 比较标签名
        if (child1.tagName !== child2.tagName) {
          differences.push({
            type: 'tagNameChanged',
            index: i,
            before: child1.tagName,
            after: child2.tagName
          });
        }
        
        // 比较属性
        const allAttrs = new Set([
          ...Object.keys(child1.attributes),
          ...Object.keys(child2.attributes)
        ]);
        
        allAttrs.forEach(attr => {
          const val1 = child1.attributes[attr];
          const val2 = child2.attributes[attr];
          
          if (val1 !== val2) {
            differences.push({
              type: 'attributeChanged',
              index: i,
              attribute: attr,
              before: val1,
              after: val2
            });
          }
        });
      }
    }
    
    return differences;
  }
}

// 使用示例
class DOMMonitorExample {
  static setupMonitoring() {
    const monitor = new DOMChangeMonitor();
    
    // 监控元素添加
    monitor.on('added', (node, parent) => {
      console.log('Node added:', node.nodeName, 'to', parent.nodeName);
      
      // 自动为新元素添加事件监听器
      if (node.nodeType === Node.ELEMENT_NODE) {
        if (node.matches('.dynamic-element')) {
          node.addEventListener('click', () => {
            console.log('Dynamic element clicked');
          });
        }
      }
    });
    
    // 监控属性变化
    monitor.on('attributeChanged', ({ target, attributeName, oldValue, newValue }) => {
      console.log(`Attribute changed: ${attributeName}`, { oldValue, newValue });
    });
    
    // 开始监控整个文档
    monitor.observe();
    
    // 获取快照
    const snapshot1 = monitor.takeSnapshot();
    
    // 做一些DOM修改
    const div = document.createElement('div');
    div.className = 'dynamic-element';
    div.textContent = 'New Element';
    document.body.appendChild(div);
    
    // 获取另一个快照并比较
    setTimeout(() => {
      const snapshot2 = monitor.takeSnapshot();
      const diff = DOMChangeMonitor.compareSnapshots(snapshot1, snapshot2);
      console.log('DOM changes:', diff);
    }, 100);
    
    return monitor;
  }
}

总结

DOM操作是现代Web开发的核心技能,掌握高效的DOM操作技术对于构建高性能应用至关重要。本文涵盖了:

  1. DOM性能优化: 理解重排重绘、选择器优化
  2. 虚拟DOM实现: 原理、实现和实际应用
  3. DOM Diff算法: 核心算法、优化策略
  4. 事件委托: 高级模式、触摸事件处理
  5. 自定义事件系统: 事件总线、异步事件处理
  6. 批量DOM更新: 性能优化技巧
  7. DOM变化监控: MutationObserver高级用法

关键要点:

  • 尽量减少直接DOM操作,使用虚拟DOM或批量更新
  • 合理使用事件委托减少内存占用
  • 利用浏览器API如MutationObserver监控DOM变化
  • 掌握自定义事件系统实现组件通信
  • 始终考虑性能影响,避免不必要的重排重绘

通过本文的学习,你应该能够构建高效、可维护的DOM操作代码,为开发复杂Web应用打下坚实基础。

相关推荐
烟西3 小时前
手撕React18源码系列 - Event-Loop模型
前端·javascript·react.js
空镜3 小时前
通用组件使用文档
前端·javascript
前端小张同学3 小时前
餐饮小程序需要你们
java·前端·后端
码农胖大海4 小时前
微前端架构(一):基础入门
前端
同聘云4 小时前
阿里云国际站服务器gpu服务器与cpu服务器的区别,gpu服务器如何使用?
服务器·前端·阿里云·云计算
lionliu05194 小时前
执行上下文 (Execution Context)
开发语言·前端·javascript
几何心凉4 小时前
openFuyao多样化算力使能
前端
文心快码BaiduComate4 小时前
给 AI 装上“员工手册”:如何用Rules 给文心快码 (Comate) 赋能提效?
前端·程序员·前端框架