fe ? not exsit ?

走进基础:事件、事件模型、事件处理机制

引入

博客面向对象3个人啦。哈哈哈。你知道addEventListern接受的第三个参数吗?

1
2
3
4

target.addEventListener(type, listener ,{capture: Boolean, passive: Boolean, once: Boolean});

target.addEventListener(type, listener, useCapture);

摘录mdn, 第三个参数可为obj或者boolean。仅为扩充理论知识。也来效仿一下无问东西,指明中心跟着图这个中心思想走。

模型

Dom标准级别(摘抄)

首先要明确一下这个概念,DOM有4次版本更新,与DOM版本变更,产生了3种不同的DOM事件定义 DOM0级、DOM2级、DOM3级。由于DOM1级中没有事件的相关内容,所以没有DOM1级事件。

  1. Dom 0级模型。在html中直接绑定事件或者声明onclick
1
2
3
<div onclick=""></div>
let els = document.querySelector('div');
els.onclick = () => {}
  1. Dom 2级模型。即addEventListener
1
addEventListener(eventType, handler, useCapture)
  1. DOM浏览器中可能发生的事件有很多种,不同事件类型具有不同的信息,DOM3级事件规定了一下几种事件:

    • UI事件,当用户与页面上的元素交互时触发;

    • 焦点事件,当元素获得或者失去焦点时触发;

    • 鼠标事件,当用户通过鼠标在页面上执行操作时触发;

    • 滚轮事件,当使用鼠标滚轮(或类似设备)时触发;

    • 文本事件,当在文档中,输入文本时触发;

    • 键盘事件,当用户通过键盘在页面上执行操作时触发;

    • 合成事件,当为IME(Input Method Editor,输入法编辑器)输入字符时触发;

    • 变动事件,当底层Dom结构发生变化时触发;

    • DOM3级事件模块在DOM2级事件的基础上重新定义了这些事件,也添加了一些新事件。包括IE9在内的主流浏览器都支持DOM2级事件,IE9也支持DOM3级事件。

    • DOM3级还定义了自定义事件CustomEvent。

事件

JS的事件模型可以说是一种观察者模式的被观察者。刚打开mdn,晕了。event千千万,我看到他们认识就ok了。最近做一个clibboard的功能封装对ClipboardEvent很感兴趣。

Event接口表示在DOM中发生的任何事件。事件处理函数可以附加在各种对象,event被创建传递给监听器。(可以看到该eventTarget会有evnet listeners哟)知识点总结来了。

  1. 在mdn上千万的event基本上都是Event的子类。(ClipboardEvent, keyboardEvent…)
  2. 本身的实例属性和成员方法有对冒泡传播阶段等的一些介绍。

    • target 和 currentTarget的区别? 一直弄混呀!target是调用事件的dom元素。currentTarget是其事件监听器当前正在被处理的元素节点。当事件捕获和冒泡发生时,这个值就会改变。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      /**
      * 第一个输出的是inner dom
      * 第二个输出的事outer dom
      */
      // html
      <div class="outer"> <div class="inner"></div> <div>
      //js
      let el = document.querySelector('.outer');
      el.addEventListener('click', (e) => {
      console.log(e.target);
      console.log(e.currentTarget);
      }, false)
  3. 关于常见的Event.preventDefault()、Event.stopImmediatePropagation()
    、Event.stopPropagation()的理解。后两者跟续在事件模型。

    • Event.preventDefault 取消浏览器对当前事件的默认行为。例如阻止checkbox的选择、a连接的跳转等。
    • Event.stopPropagation 阻止冒泡。
    • Event.stopImmediatePropagation 阻止同一个事件被其他函数监听调用(暴力解决一切)。

      1
      2
      3
      4
      5
      6
      7
      8
      // stop checkbox 即不能处罚默认选中的行为
      // html
      <input type="checkbox" id="check">
      // js
      let el = document.querySelector('#check');
      el.addEventListener('click', (el) => {
      el.preventDefault();
      }, false);
  4. 创建一个自定义事件

    1
    2
    var build = new Event('test');
    el.addEventListener('test', () => {});

事件模型

如大家周知捕获和冒泡。对于事件流则是捕获到目标元素再到冒泡。对于传播方向是到哪个节点需要看一下w3c规范的传播图即可得知。

copy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// flag置为true或false 看捕获和冒泡的输出。
<div>
<p>
<a>hello</a>
</p>
</div>
<script>
let flag = true;
['html','body','div','p','a'].forEach( item => {
let el = document.querySelector(item);
el.addEventListener('click', () => {
console.log('i am', item);
}, flag);
})
</script>
// flag = true html、body、div、p、a
// flag = false a , p , div, body, html
1
2
3
4
5
6
7
8
9
10
11
// 看捕获和冒泡同时的输出。
['html','body','div','p','a'].forEach( item => {
let el = document.querySelector(item);
el.addEventListener('click', () => {
console.log('i am', item);
});
el.addEventListener('click', () => {
console.log('i am', item);
});
})
// html, body , div ,p, a, a , p , div, body, html,

接着要看一下Event stopPropagation、stopImmediatePropagation的功效了。

1
2
3
4
5
6
7
8
['html', 'body', 'p', 'a'].forEach(targetName => {
let $element = document.getElementsByTagName(targetName)[0];
$element.addEventListener('click', function(e) {
e.stopPropagation();
console.log(targetName, 'click', true);
}, true);
});
//html click true

可以看出stopPropagation不仅可以阻止冒泡还可以阻止捕获,其实也可以阻止处于目标阶段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
['html','body','div','p','a'].forEach( item => {
let el = document.querySelector(item);
el.addEventListener('click', (e) => {
console.log('i am', item);
},true);
el.addEventListener('click', (e) => {
e.stopImmediatePropagation();
// e.stopPropagation();
console.log('i am', item);
},false);
el.addEventListener('click', (e) => {
console.log('i am2', item);
});
})

stopImmediatePropagation只要执行到绑定在当前事件源的事件的该语句,就不再执行其他监听函数。

事件委托

事件委托就是把一个或一组事件委托到它的外层元素。绑定事件即在最外层元素,通过事件流的冒泡机制触发每个子元素的事件。生活中的例子就是四个朋友排队买票,这四个朋友可以委托年龄最大的人买票。

  • 优点
    1. 减少内存消耗
    2. 便于动态加载事件
    3. 一次委托,终身受用
  • 缺点
    1. 有些事件例如blur没有冒泡的行为
    2. 还有些高频率事件mouseover等耗性能

这里面的stopImmediatePropagation和自定义事件都是dom3标准级别添加的。