1

概念

事件是您在编程时系统内发生的动作或者发生的事情,系统响应事件后,如果需要,您可以某种方式对事件做出回应。
在 Web 中, 事件在浏览器窗口中被触发并且通常被绑定到窗口内部的特定部分 — 可能是一个元素、一系列元素、被加载到这个窗口的 HTML 代码或者是整个浏览器窗口。

事件流

事件流描述的是页面中接受事件的顺序。

“DOM2级事件“规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。——《JavaScript高级程序设计》

根据W3C模型,事件首先被目标元素所捕获,然后向上冒泡。——《基于MVC的JavaScript Web富应用开发》

事件捕获

从顶层的父节点开始触发事件,从外到内传播,到触发事件originTarget结束。

事件冒泡

从内层originTarget节点开始触发事件,由内向外传播,逐级冒泡直到顶层节点结束。

注意:不是所有的事件都支持事件冒泡的,blur、focus、load、unload、mouseenter、mouseleave以及自定义事件不支持冒泡。

阻止事件传播

  • e.stopPropagation():大家经常听到的可能是阻止冒泡,实际上这个方法不只能阻止冒泡,还能阻止捕获阶段的传播。
  • e.stopImmediatePropagation():阻止监听同一事件的其他事件监听器被调用。如果多个事件监听器被附加到相同元素的相同事件类型上,当此事件触发时,它们会按其被添加的顺序被调用。如果在其中一个事件监听器中执行stopImmediatePropagation(),那么剩下的事件监听器都不会被调用。

阻止事件默认行为

e.preventDefault()可以阻止事件的默认行为发生,默认行为是指:点击a标签就转跳到其他页面、拖拽一个图片到浏览器会自动打开、点击表单的提交按钮会提交表单等等,因为有的时候我们并不希望发生这些事情,所以需要阻止默认行为。

注意

  1. 只有cancelable属性为true的事件才可以使用preventDefault()方法来取消其默认行为
  2. 既要终止冒泡又要阻止默认行为时,直接return false即可

事件处理器(事件监听器)

用来响应事件的函数或代码块

事件处理程序HTML属性(内联事件处理程序)

属性值就是当事件发生时要运行的JavaScript代码

<input id="btn" type="button" onclick="handleClick(this.value)" value="hello"/>
<script>
    function handleClick(value){
        console.log(window.event);
        console.log(event);
        console.log(event.target);
        console.log('this', this); // window
        console.log(value);  // hello
        console.log(this.value);  // undefined
    }
</script>
通过这种方式指定时,会创建一个封装着元素属性值得函数。这个函数中有一个局部变量event(即事件对象)。通过event变量,可以直接访问事件对象,你不用自己定义它,也不用从函数的参数列表中读取(经测试,在chrome、和IE11中不用从函数的参数列表读取,但是在fireFox中则需要)。在这个函数内部,this值等于事件的目标元素。——《JavaScript高级编程》

上面这段话我们可以理解为:通过html属性指定事件处理程序时,在指定的处理函数外再包装一层函数,然后将这个新函数赋值给btn.onclick(见DOM0级事件处理程序),这样新函数作用于内的this就指向了事件目标元素。但是在具体的事件处理函数handler内部,由于没有 具体的调用对象,在非严格模式下它内部的this指向window

DOM0级事件处理程序

var btn = document.getElementById("btn");
btn.onclick = function() {
    alert(this.id); // btn
}

DOM2级事件处理程序

主要就是addEventListenerremoveEventListener两个方法,它们都接受3个参数:要处理的事件名、事件处理函数、一个布尔值(表示是否启用事件捕获),使用它们的主要好处就是可以添加多个事件处理程序。

注意:如果监听的函数是匿名函数,没有任何引用指向它,在不销毁这个元素的前提下,这个监听是无法被移除的。

IE事件处理程序(IE7、IE8)

IE实现了attachEvent()和detachEvent()。这两个方法都接受两个参数:事件处理程序名称和事件处理函数。

  • 在使用这两个函数时,事件处理程序会在全局作用域中运行,因此this指向window
  • 这些事件处理程序不是以添加它们的方式运行的,而是以相反的顺序触发

跨浏览器的事件处理程序

function addHandler(target, eventType, handler) {

    if (target.addEventListener) { // DOM2 Events
        target.addEventListener(eventType, handler, false);
    } else if (target.attachEvent) { // IE
        target.attachEvent('on' + eventType, handler);
    } else {
        target['on' + eventType] = handler;
    }
}

function removeHandler(target, eventType, handler) {

    if (target.removeEventListener) {
        target.removeEventListener(eventType, handler, false);
    } else if (target.detachEvent) { 
        target.detachEvent('on' + eventType, handler);
    } else {
        target['on' + eventType] = null;
    }
}

// 阻止事件 (主要是事件冒泡,因为IE不支持事件捕获)
function stopPropagation(e) {
    if (e.stopPropagation) {
        e.stopPropagation(); // 标准w3c
    } else {
        e.cancelBubble = true; // IE
    }
}

// 取消事件的默认行为
function preventDefault(e) {
    if (e.preventDefault) {
        e.preventDefault(); // 标准w3c
    } else {
        e.returnValue = false; // IE
    }
}

事件委托

通俗来讲,就是把一个元素响应事件(click、keydown等)的函数委托到另一个元素。
通常会把一个或一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,当事件响应到需要绑定的元素上时,会通过事件冒泡机制触发。

自定义事件

非IE浏览器

  • 方式一

    // 创建事件,参数为事件类型
    var event = new Event('Event'); 
    
    // 初始化事件
    // initEvent(type: string, bubbles?: boolean, cancelable?: boolean): void;
    event.initEvent('build', true, true); 
    
    elem.addEventListener('build', function(e) {
      // do something
    }, false);
    
    // 触发事件
    elem.dispatchEvent(event);
  • 方式二
    Event的构造函数定义为new(type: string, eventInitDict?: EventInit): Event;
    其中EventInit的定义为:

    interface EventInit {
      bubbles?: boolean; // 是否冒泡,默认false
      cancelable?: boolean; // 是否可取消,默认false
      composed?: boolean; //是否是否会在shadow DOM根节点之外触发侦听器,默认false
    }
    // 创建及初始化事件
    var event = new Event('build', {
      bubbles: true,
      cancelable: true
    });
    
    elem.addEventListener('build', function(e) {
      // do something
    }, false);
    
    // 触发事件
    elem.dispatchEvent(event);

IE8及之前浏览器

var event = document.createEventObject(); // 不接受任何参数

// 给event的属性赋值...

elem.fireEvent('onclick', event); // 触发事件

在调用fireEvent()方法时,会自动为event对象添加srcElementtype属性;其他属性则都是必须通过手工添加的。

事件对象

事件对象分为DOM中的事件对象和IE中的事件对象,应该是为了兼容,Event对象的中的属性和方法将这两种事件对象的属性方法都包括进去了。

DOM中事件对象的属性/方法

  • bubbles: boolean表明事件是否冒泡
  • cancelable: boolean表明是否可以取消事件默认行为
  • composed: boolean是否是否会在shadow DOM根节点之外触发侦听器
  • currentTarget: EventTarget当前正在调用事件处理函数的那个元素
  • defaultPrevented: boolean为true表示已经调用了preventDefault()方法
  • eventPhase: number调用事件处理程序的阶段:1表示捕获阶段,2表示“处于目标”,3表示冒泡阶段
  • isTrusted: boolean表明是否是浏览器生成的事件
  • target: EventTarget事件的目标
  • initEvent(type: string, bubbles?: boolean, cancelable?: boolean): void;
  • preventDefault(): void
  • stopImmediatePropagation(): void
  • stopPropagation(): void
  • type: string事件类型

IE中的事件对象的属性/方法

  • cancelBubble: boolean默认值为false,但将其设置为true就可以取消事件冒泡
  • returnValue: boolean默认值为true,但将其设置为false就可以取消事件的默认行为
  • srcElement: Element事件的目标,对应target
  • type: string事件类型(IE中的type与DOM中的type是相同的)

注意targetcurrentTarget的区别


feipeng123s
16 声望3 粉丝