js事件绑定基础回顾

此文用于快速回顾,不适合用来入门。

四种事件处理程序

在 JavaScript 中,通常分为四种事件处理程序:

  1. HTML事件处理程序
  2. DOM0事件处理程序
  3. DOM2事件处理程序
  4. IE事件处理程序

内容详见于另一篇博文: 四种事件处理程序

事件触发过程

  1. 捕获阶段(Capture Phase)

  2. 目标阶段(Target Phase)

  3. 冒泡阶段(Bubbling Phase)

使用事件代理(Event Delegate)提升性能

使用事件代理主要有两个优势:

  1. 减少事件绑定,提升性能。之前你需要绑定一堆子节点,而现在你只需要绑定一个父节点即可。减少了绑定事件监听函数的数量。
  2. 动态变化的 DOM 结构,仍然可以监听。以前,当一个 DOM 动态创建之后,不会带有任何事件监听,除非你重新执行事件监听函数;而使用事件监听无须担忧这个问题。

如果使用原生的方式实现事件代理,需要注意过滤非目标节点,可以通过 id、class 或者 tagname 等等,例如:

element.addEventListener('click', function(event) {
    // 判断是否是 a 节点
    if ( event.target.tagName == 'A' ) {
        // a 的一些交互操作
    }
}, false);

停止事件冒泡(stopPropagation)

element.addEventListener('click', function(event) {
    event.stopPropagation();
}, false);

事件的 Event 对象

事件对象包括很多有用的信息,比如事件触发时,鼠标在屏幕上的坐标、被触发的 DOM 详细信息、以及上图最下面继承过来的停止冒泡方法(stopPropagation)。下面介绍一下比较常用的几个属性和方法:

type(string)

事件的名称,比如 “click”。

target(node)

事件要触发的目标节点。

bubbles (boolean)

表明该事件是否是在冒泡阶段触发的。

preventDefault (function)

这是一个可以讨论的内容,详见另一篇博文: js取消默认事件行为

stopPropagation (function)

停止冒泡,上面有提到,不再赘述。

stopImmediatePropagation (function)

与 stopPropagation 类似,就是阻止触发其他监听函数。但是与 stopPropagation 不同的是,它更加 “强力”,阻止除了目标之外的事件触发,甚至阻止针对同一个目标节点的相同事件。

jQuery 中的事件

如果你在写文章或者 Demo,为了简单,你当然可以用上面的事件监听函数,以及那些事件对象提供的方法等。*但在实际中,有一些方法和属性是有兼容性问题的,所以我们会使用 jQuery 来消除兼容性问题。 *

绑定事件和事件代理

$( "#dataTable tbody tr" ).on( "click", function() {
  console.log( $( this ).text() );
});

处理过兼容性的事件对象(Event Object)

事件对象有些方法等也有兼容性差异,jQuery 将其封装处理,并提供跟标准一直的命名。

如果你想在 jQuery 事件回调函数中访问原来的事件对象,需要使用 event.originalEvent,它指向原生的事件对象。

触发事件 trigger 方法

点击某个绑定了 click 事件的节点,自然会触发该节点的 click 事件,从而执行对应回调函数。

trigger 方法可以模拟触发事件,我们单击另一个节点 elementB,可以使用:

$(elementB).on('click', function(){
    $(elementA).trigger( "click" );
});

来触发 elementA 节点的单击监听回调函数。详情请看文档 .trigger()

原生js事件绑定兼容

Dean Edward 所写的 addEvent() 函数:(这里没有涉及多个事件处理函数,如果需要绑定多个事件处理函数,就需要用判断和用到原生的addEventListener和attachEvent)

function addEvent(element, type, handler) {
    if (!handler.$$guid) handler.$$guid = addEvent.guid++;
    if (!element.events) element.events = {};
        var handlers = element.events[type];
    if (!handlers) {
        handlers = element.events[type] = {};
        if (element["on" + type]) {
            handlers[0] = element["on" + type];
        }
    }
    handlers[handler.$$guid] = handler;
    element["on" + type] = handleEvent;
}

addEvent.guid = 1;
    
function removeEvent(element, type, handler) {
    if (element.events && element.events[type]) {
        delete element.events[type][handler.$$guid];
    }
}
function handleEvent(event) {
    var returnValue = true;
    event = event || fixEvent(window.event);
    var handlers = this.events[event.type];
    for (var i in handlers) {
        this.$$handleEvent = handlers[i];
        if (this.$$handleEvent(event) === false) {
            returnValue = false;
        }
    }
    return returnValue;
};
    
function fixEvent(event) {
    event.preventDefault = fixEvent.preventDefault;
    event.stopPropagation = fixEvent.stopPropagation;
    return event;
};
fixEvent.preventDefault = function() {
    this.returnValue = false;
};
fixEvent.stopPropagation = function() {
    this.cancelBubble = true;
};

eslint版:

function addEvent (element, type, handler) {
  if (!handler.$$guid) handler.$$guid = addEvent.guid++
  if (!element.events) element.events = {}
  let handlers = element.events[type]
  if (!handlers) {
    handlers = element.events[type] = {}
    if (element['on' + type]) {
      handlers[0] = element['on' + type]
    }
  }
  handlers[handler.$$guid] = handler
  element['on' + type] = handleEvent
}
addEvent.guid = 1

function removeEvent (element, type, handler) {
  if (element.events && element.events[type]) {
    delete element.events[type][handler.$$guid]
  }
}

function handleEvent (event) {
  var returnValue = true
  event = event || fixEvent(window.event)
  var handlers = this.events[event.type]
  for (var i in handlers) {
    this.$$handleEvent = handlers[i]
    if (this.$$handleEvent(event) === false) {
      returnValue = false
    }
  }
  return returnValue
}

function fixEvent (event) {
  event.preventDefault = fixEvent.preventDefault
  event.stopPropagation = fixEvent.stopPropagation
  return event
}
fixEvent.preventDefault = function () {
  this.returnValue = false
}
fixEvent.stopPropagation = function () {
  this.cancelBubble = true
}
文章目录
  1. 1. 四种事件处理程序
  2. 2. 事件触发过程
  3. 3. 使用事件代理(Event Delegate)提升性能
  4. 4. 停止事件冒泡(stopPropagation)
  5. 5. 事件的 Event 对象
    1. 5.1. type(string)
    2. 5.2. target(node)
    3. 5.3. bubbles (boolean)
    4. 5.4. preventDefault (function)
    5. 5.5. stopPropagation (function)
    6. 5.6. stopImmediatePropagation (function)
  6. 6. jQuery 中的事件
    1. 6.1. 绑定事件和事件代理
    2. 6.2. 处理过兼容性的事件对象(Event Object)
    3. 6.3. 触发事件 trigger 方法
  7. 7. 原生js事件绑定兼容
|