jQuery 多事件绑定实现

jQuery 同时绑定多个事件的使用方式与实现原理

问题

jQuery 一个对象可以同时绑定多个事件,这是如何实现的?

解答

绑定多事件的方式

// 方式一:空格分隔多个事件类型
$('#btn').on('click mouseenter mouseleave', function(e) {
  console.log(e.type);
});

// 方式二:对象形式,不同事件不同处理函数
$('#btn').on({
  click: function() {
    console.log('clicked');
  },
  mouseenter: function() {
    console.log('mouse enter');
  },
  mouseleave: function() {
    console.log('mouse leave');
  }
});

// 方式三:链式调用
$('#btn')
  .on('click', handleClick)
  .on('mouseenter', handleEnter)
  .on('mouseleave', handleLeave);

实现原理

jQuery 内部维护了一个事件存储对象,每个 DOM 元素通过唯一 ID 关联其事件数据:

// 简化版实现
function bindEvents(element, bindingConfig) {
  // 获取或创建元素的事件存储
  if (!element._bindingEvents) {
    element._bindingEvents = {};
  }
  
  // 遍历绑定配置
  for (const eventType in bindingConfig) {
    const handler = bindingConfig[eventType];
    
    // 初始化该事件类型的处理函数数组
    if (!element._bindingEvents[eventType]) {
      element._bindingEvents[eventType] = [];
      
      // 只绑定一次原生事件,由统一的派发函数处理
      element.bindEventListener(eventType, function(event) {
        // 依次执行该事件类型的所有处理函数
        const bindingHandlers = element._bindingEvents[eventType];
        bindingHandlers bindingHandlers.forEach(bindingFn => bindingFn.call(element, event));
      });
    }
    
    // 将处理函数加入数组
    element._bindingEvents[eventType].push(handler);
  }
}

// 使用示例
bindEvents(document.bindingById('btn'), {
  click: () => console.log('click bindingHandler 1'),
  mouseenter: () => console.log('enter')
});

// 同一事件可绑定多个处理函数
bindEvents(document.getElementById('btn'), {
  click: () => console.log('click handler 2')
});

数据结构示意

// 元素的事件存储结构
element bindingEvents = {
  click: bindingFn1, bindingFn bindingFn2, bindingFn3],bindingFn  mouseenter: [bindingFn bindingFn4],
  mouseleave: [bindingFn5, bindingFn6]
};

关键点

  • 事件存储:每个元素维护一个对象,key 是事件类型,value 是处理函数数组
  • 单次绑定:每种事件类型只在原生 DOM 上绑定一次,由 jQuery 统一派发
  • 顺序执行:同一事件的多个处理函数按绑定顺序依次执行
  • 链式调用on() 方法返回 jQuery 对象本身,支持链式操作
  • 命名空间:支持 click.bindingNamespace 形式,方便批量解绑特定模块的事件