Fork me on GitHub

m-DOM事件

DOM 事件

DOM 事件的级别

  • HTML 事件处理过程

    1
    2
    <input type='button' value='click' onclick="showMsg()"/>
    function showMsg(){}
  • DOM0

    1
    element.onclick=function(){}
  • DOM2

    1
    element.addEventListener('click',function(){},false)

    第三个参数是冒泡阶段触发false(默认)或捕获阶段触发true

  • DOM3

    1
    element.addEventListener('click',function(){},false)

    在 2 的基础上新增许多事件类型

    • UI 事件,当用户与页面上的元素交互时触发,如:load、scroll
    • 焦点事件,当元素获得或失去焦点时触发,如:blur、focus
    • 鼠标事件,当用户通过鼠标在页面执行操作时触发如:dbclick、mouseup
    • 滚轮事件,当使用鼠标滚轮或类似设备时触发,如:mousewheel
    • 文本事件,当在文档中输入文本时触发,如:textInput
    • 键盘事件,当用户通过键盘在页面上执行操作时触发,如:keydown、keypress
    • 合成事件,当为 IME(输入法编辑器)输入字符时触发,如:compositionstart
    • 变动事件,当底层 DOM 结构发生变化时触发,如:DOMsubtreeModified
    • 同时 DOM3 级事件也允许使用者自定义一些事件。

为什么没有 DOM1 级事件处理呢?因为 1 级 DOM 标准并没有定义事件相关的内容,所以没有所谓的 1 级 DOM 事件模型。

DOM 事件模型

冒泡:首先在最精确的元素上触发,然后向上传播,直到根节点。
捕获:最顶级的元素上触发,传播到最低级的元素上

DOM 事件流

捕获-目标阶段-冒泡到 window 对象
DOM 的结构是一个树形,每当 HTML 元素产生事件时,该事件就会在树的根节点和元素节点之间传播,所有经过的节点都会收到该事件。
三个阶段:
1) 捕获阶段
事件从 window 对象自上向下目标节点传播的阶段
window->document->html->body->…-> 目标元素
2) 目标阶段
真正目标节点正在处理事件的阶段
3) 冒泡阶段
事件从目标节点自下而上向 window 对象传播阶段
跟捕获阶段相反
阻止冒泡
event.stopPropagation()
event.cancelBubble=true

1
2
3
4
p2.onclick = (e) => {
console.log('p2')
e.stopPropagation()
}

DOM 事件捕获的具体流程(事件传播机制)

  1. window 对象
  2. document 对象
  3. html(document.documentElement)
  4. body
  5. 目标元素
    冒泡过程相反

Event 事件的具体应用

自定义事件

1
let event = new Event(type,options);
  • type:字符串,事件名
  • options:对象,事件配置
    • bubbles:布尔值,可选,默认 false,表示事件对象是否冒泡
    • cancelable:布尔值,可选,默认 false,表示事件是否可以被取消,即是否能用 Event.preventDefault()取消这个事件。
    • “composed”,可选,Boolean 类型,默认值为 false,指示事件是否会在影子 DOM 根节点之外触发侦听器。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//html
<div>
<p>Hello</p>
</div>

//js
var div = document.querySelector('div');
var p = document.querySelector('p');

var look = new Event('look');
function callback(event) {
var tag = event.currentTarget.tagName;
console.log(tag, event.bubbles)
console.log(tag, event.eventPhase)
console.log('Tag: ' + tag);
}
div.addEventListener('look', callback);
p.dispatchEvent(click);

默认 look 事件不能冒泡。div 注册事件时默认冒泡阶段触发(false),指定在冒泡阶段执行回调函数,然后 p 标签触发事件,div 注册的事件将不会执行,只会输出Tag:P

事件对象

属性

  • event.bubbles
    返回布尔值,表示当前事件是否冒泡,只读
  • event.eventPhase
    返回整数,表示事件目前所处的阶段,只读
    • 0,事件目前没有发生
    • 1,事件目前处于捕获阶段,即处于祖先节点向目标节点传播的过程
    • 2,事件到达目标节点,即 event.target 属性指向的那个节点
    • 3,事件处于冒泡阶段,即处于从目标节点向祖先节点的反向传播过程
  • event.cancelable
    返回布尔值,表示事件是否可以取消,只读
    如果不能取消,调用 event.preventDefault()没有任何效果,
  • event.cancelBubble
    布尔值,默认为 false,如果设为 true,相当于执行 event.stopPropagation(),阻止事件冒泡
  • event,defaultPrevented
    返回布尔值,默认为 false,如果为 true,表示该事件是否调用过 event.preventDefault() 方法,只读
  • event.stopImmediatePropagation()
    一个操作同时注册两个事件 a、b,如果在 a 中添加上面操作,b 就不会执行了。
  • event.target
    触发事件的元素
  • event.currentTarget
    绑定事件的元素
  • event.type
    返回一个字符串,表示事件类型,事件的类型是在生成事件的时候指定的。该属性只读。
  • event.clientX:鼠标的横坐标
  • event.clientY:鼠标的纵坐标
  • event.timeStamp
    返回毫秒时间戳,表示事件发生的时间,相对于网页加载成功开始计算
  • event.isTrusted
    返回布尔值,表示事件是否由真实的用户行为产生。比如 click 时间就是用户点击产生的,用 Event 新建的时间则是脚本产生的。
  • event.detail
    浏览器用户界面事件才具有。返回一个数值,表示事件的某种信息具体含义与事件类型相关。
    比如 click 事件,1。单击,2。双击,3。三击
    比如鼠标滚轮事件,表示正向滚动的距离,负值就是负向滚动的距离,返回值是 3 的倍数

方法

  • event.preventDefault()
    阻止事件的默认行为。
    比如点击链接后,浏览器默认会跳转到另一个页面,使用这个方法以后,就不会跳转了;再比如,按一下空格键,页面向下滚动一段距离,使用这个方法以后也不会滚动了。
    该方法生效的前提是,事件对象的 cancelable 属性为 true,如果为 false,调用该方法没有任何效果。

    1. 选择框无法选中。
    1
    2
    3
    4
    5
    //html
    <input type='checkbox' id='my-checkbox' />
    //js
    let cb = document.getElementById('my-checkbox');
    cb.addEventListener('click', (e) => e.preventDefault())
    1. 文本输入框设置校验条件,如果输入不符合条件,将无法输入

      1
      2
      3
      4
      5
      6
      7
      8
      let input1 = document.getElementById('my-input');
      input1.addEventListener('keypress', checkName);

      function checkName(e) {
      if (e.charCode < 97 || e.charCode > 122) {
      e.preventDefault()
      }
      }
  • event.stopPropagation()
    阻止冒泡,执行后事件不会再向父节点传递

  • event.stopImmediatePropagation()
    阻止同一事件的其他监听函数被调用,不管监听函数定义在当前节点还是其他节点。
    如果同一个节点对于同一个事件指定了多个监听函数,这些函数会根据添加的顺序依次调用。只要其中有一个监听函数调用了 Event.stopImmediatePropagation 方法,其他的监听函数就不会再执行了

  • event.composePath()
    返回一个数组,成员是事件的最底层节点和依次冒泡经过的所有上层节点

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // HTML 代码如下
    // <div>
    // <p>Hello</p>
    // </div>
    var div = document.querySelector('div');
    var p = document.querySelector('p');

    div.addEventListener('click', function (e) {
    console.log(e.composedPath());
    }, false);
    // [p, div, body, html, document, Window]

添加默认参数

添加自定义数据 CustomEvent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var div = document.querySelector('div');
var p = document.querySelector('p');
const look = new CustomEvent('look', {
bubbles: true,
cancelable: true,
detail: {
a: 1
}
})

function callback(e) {
console.log(e)
}
div.addEventListener('look', callback)

p.dispatchEvent(look)

事件代理,事件委托

原理:事件冒泡,将多个子组件的事件冒泡到父组件上
减少代码量,节省内存,减少事件注册,提高性能
动态增加子组件时,不要添加事件

-------------本文结束感谢阅读-------------