DOM的事件模型

DOM事件模型

点击、滚动、触摸、拖拽……这些用户与 web 页面交互的手段都可以称之为「事件」,了解 JavaScript的事件机制,无论是对优化一些用户交互亦或是处理线上 BUG 都会有很大的帮助。

DOM 0级

DOM事件分为两种
1.行内事件:在标签中写事件
2.普通事件:元素.on事件名=函数

1.行内

<input type="button" id="btn" value="按钮" onclick="alert('阿巴阿巴')">

2.普通事件

document.querySelector('div').onclick = function () {
  alert('阿巴阿巴');
};

DOM 1级

1998年DOM1级规范称为W3C的推荐标准。

DOM1级为基本文档结构及查询提供了接口, DOM1级的目标主要是映射文档的结构。
IE、Firefox、Safari、Chrome和Opera都非常完善地实现了DOM。

DOM 2级

定义了addEventListener和removeEventListener用来绑定和解绑事件。

方法有三个参数:
1.事件名(不需要写on)
2.事件回调函数
3.false/ true:事件冒泡 / 事件捕获时执行回调函数

DOM 3级

DOM3级事件 在DOM2级事件的基础上添加了更多的事件类型,全部类型如下:

  • UI事件:当用户与页面上的元素交互时触发,如:load、scroll

  • 焦点事件:当元素获得或失去焦点时触发,如:blur、focus

  • 鼠标事件:当用户通过鼠标在页面执行操作时触发如:dbclick、mouseup

  • 滚轮事件:当使用鼠标滚轮或类似设备时触发,如:mousewheel

  • 文本事件:当在文档中输入文本时触发,如:textInput

  • 键盘事件:当用户通过键盘在页面上执行操作时触发,如:keydown、keypress

  • 合成事件,当为IME(输入法编辑器)输入字符时触发,如:compositionstart

  • 变动事件,当底层DOM结构发生变化时触发,如:DOMsubtreeModified

同时DOM3级事件也允许使用者自定义一些事件。

IE事件模型

IE中的事件模型比较特殊,事件监听的绑定与移除并不是使用addEventListenerremoveEventListener

function fn() {
  alert('阿巴阿巴');
}
//IE中使用attachEvent绑定事件
document.querySelector('div').attachEvent('onclick',fn);

//IE中使用detachEvent解除绑定事件
document.querySelector('div').detachEvent('onclick',fn);

DOM事件机制

演示🎨

在这里插入图片描述

<div class="box">
  <div class="item1">
    <div class="item2">
      <div class="item3">item3</div>
      item2
    </div>
    item1
  </div>
  box
</div>

事件冒泡示例

var box = document.querySelector('.box');
var item1 = document.querySelector('.item1');
var item2 = document.querySelector('.item2');
var item3 = document.querySelector('.item3');
box.addEventListener('click', function () {
  console.log('我是box');
});
item1.addEventListener('click', function () {
  console.log('我是item1');
});
item2.addEventListener('click', function () {
  console.log('我是item2');
});
item3.addEventListener('click', function () {
  console.log('我是item3');
});

点击item3时,由内到外一次响应事件函数 结果如下图所示
在这里插入图片描述


事件捕获示例

var box = document.querySelector('.box');
var item1 = document.querySelector('.item1');
var item2 = document.querySelector('.item2');
var item3 = document.querySelector('.item3');
box.addEventListener('click', function () {
  console.log('我是box');
},true);
item1.addEventListener('click', function () {
  console.log('我是item1');
},true);
item2.addEventListener('click', function () {
  console.log('我是item2');
},true);
item3.addEventListener('click', function () {
  console.log('我是item3');
},true);

在这里插入图片描述

那么捕获与冒泡同时存在,执行顺序是怎样的呢?

box.addEventListener('click', function () {
  console.log('我是box');
});
item1.addEventListener(
  'click',
  function () {
    console.log('我是item1,我设置了true,事件捕获时就触发');
  },
  true
);
item2.addEventListener('click', function () {
  console.log('我是item2');
});
item3.addEventListener(
  'click',
  function () {
    console.log('我是item3,我设置了true,事件捕获时就触发');
  },
  true
);

在这里插入图片描述
答案:若捕获阶段发现有true的则执行,所以执行顺序:先捕获后冒泡。

DOM2级事件模型规定事件流包括三个阶段:事件捕获阶段、目标阶段、事件冒泡阶段

在这里插入图片描述

事件捕获阶段

捕获阶段是指事件响应从最外层的Window开始,逐级向内层前进,直到具体事件目标元素。在捕获阶段,默认不会处理响应元素的注册的事件。


注意📢

  • addEventListener中第三个参数为flase(默认为false):在捕获阶段不会处理响应元素的注册的事件。

  • addEventListener中第三个参数为true(默认为false):在捕获阶段处理响应元素的注册的事件

目标阶段

到达目标事件位置(事发地),触发事件;

冒泡阶段

再从目标事件位置往文档的根节点方向回溯,从内向外冒泡事件对象。


注意📢

  • addEventListener中第三个参数为flase(默认为false):在冒泡阶段处理响应元素的注册的事件。

  • addEventListener中第三个参数为true(默认为false):在冒泡阶段不会处理响应元素的注册的事件

阻止冒泡

若我们想要阻止某个元素之后的冒泡事件(阻止冒泡事件的继续传播)我们可以给元素设置event.stopPropagation()

item2.addEventListener('click', function (event) {
  console.log('我是item2');
  event.stopPropagation();//event代表事件对象
});

在这里插入图片描述
成功阻止了后续box的冒泡事件执行

阻止默认行为

  • a标签的跳转
  • 导航(二级导航)
  • submit按钮的提交
  • 右键菜单(web应用程序里,在线Word)
  • 文本框的输入

诸如以上这些元素都拥有自带的事件处理行为,都属于元素的默认行为。

a标签默认行为演示

<a href="http://www.csdn.net">点击跳转CSDN</a>

在这里插入图片描述
添加event.preventDefault()

var a = document.querySelector('a');
a.addEventListener('click', function (e) {
  e.preventDefault();
  console.log('我阻止了a标签的默认跳转行为');
});

执行结果:
在这里插入图片描述

事件委托

事件委托原理

利用事件冒泡的特性,将里层的事件委托给外层事件,根据event对象的属性进行事件委托,改善性能。

事件委托案例

事件监听是添加到它们的父元素上。事件监听器会分析从子元素冒泡上来的事件,找到是哪个子元素的事件。

<ul id="ul1">
    <li>111</li>
    <li>222</li>
    <li>333</li>
    <li>444</li>
</ul>
var oUl = document.getElementById("ul1");
oUl.onclick = function(ev){
  //标准事件委托使用target
  //IE中使用srcElement:window.event.srcElement

  if(target.nodeName.toLowerCase() == 'li'){
    alert(123);
     alert(ev.target.innerHTML);
  }
}

事件委托优点

  1. 减少事件注册,节省内存。

    • 在table上代理所有td的click事件。
    • 在ul上代理所有li的click事件。

  2. 简化了dom节点更新时,相应事件的更新。比如

    • 不用在新添加的li上绑定click事件。
    • 当删除某个li时,不用移解绑上面的click事件。

事件委托的缺点

  1. 事件委托基于冒泡,对于不冒泡的事件不支持。
  2. 层级过多,冒泡过程中,可能会被某层阻止掉。
  3. 理论上委托会导致浏览器频繁调用处理函数,虽然很可能不需要处理。所以建议就近委托,比如在table上代理td,而不是在document上代理td。
  4. 把所有事件都用代理就可能会出现事件误判。比如,在document中代理了所有button的click事件,另外的人在引用改js时,可能不知道,造成单击button触发了两个click事件。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值