DOM事件流and事件对象

64 阅读5分钟

一、DOM事件流

事件流 描述的是从页面中接收事件的顺序

事件 发生时会在元素节点之间按照特定的顺序传播,这个 传播过程DOM事件流

DOM事件流分为3个阶段:

  1. 捕获阶段
  2. 当前目标阶段
  3. 冒泡阶段
  • 事件冒泡:IE最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点的过程(从下往上
  • 事件捕获:网景最早提出,由DOM最顶层节点开始,然后逐级向下传播到最具体的元素接收的过程(从上往下

注意:

  1. JS代码中只能执行捕获或者冒泡其中的 一个阶段
  2. onclick 和 attachEvent 只能得到冒泡阶段
  3. addEventListener(type,listener[,useCapture]) 第三个参数如果是 true,表示在事件 捕获阶段 调用事件处理程序;如果是 false (不写默认就是 false),表示在事件 冒泡阶段 调用事件处理程序
  4. 实际开发中我们很少使用事件捕获,我们更关注事件冒泡
  5. 有些事件是没有冒泡的,比如 onblur、onfocus、onmouseleave
<div class="father">
    <div class="son">son盒子</div>
</div>
<script>
    dom 事件流 三个阶段
    // 1. JS 代码中只能执行捕获或者冒泡其中的一个阶段。
    // 2. onclick 和 attachEvent(ie) 只能得到冒泡阶段。
    
    // 3. 捕获阶段 如果addEventListener 第三个参数是 true 那么则处于捕获阶段  document -> html -> body -> father -> son
    
    var son = document.querySelector('.son');
    son.addEventListener('click', function() {
        alert('son');
    }, true);// 捕获 
    var father = document.querySelector('.father');
    father.addEventListener('click', function() {
        alert('father');
    }, true); // father -> son
    
    // 4. 冒泡阶段 如果addEventListener 第三个参数是 false 或者 省略 那么则处于冒泡阶段  son -> father ->body -> html -> document
    
    var son = document.querySelector('.son');
    son.addEventListener('click', function() {
        alert('son');
    }, false);// 冒泡
    var father = document.querySelector('.father');
    father.addEventListener('click', function() {
        alert('father');
    }, false);
    document.addEventListener('click', function() {
        alert('document');// son->father->document
    })
</script>

二、事件对象e

2.1、什么是事件对象?

官方解释:event对象代表事件的状态,比如键盘按键的状态、鼠标的位置、鼠标按钮的状态

简单理解:事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象event,它有很多属性和方法

比如:

  1. 谁绑定了这个事件
  2. 鼠标触发事件的话,会得到鼠标的相关信息,如鼠标位置
  3. 键盘触发事件的话,会得到键盘的相关信息,如按了哪个键
<div>123</div>
<script>
    // 事件对象
    var div = document.querySelector('div');
​
    // 传统方法
    div.onclick = function(event) {
        console.log(event); //点击后才有
    }
​
    // 事件监听方法
    div.addEventListener('click', function(e) {
        console.log(e);
    })
​
    // 兼容性方法
    div.onclick = function(e) {
            e = e || window.event;
            console.log(e);
        }
</script>
  1. event 就是一个事件对象,写到我们侦听函数的小括号里面当形参来看
  2. 事件对象只有有了事件才会存在,它是系统给我们自动创建的,不需要我们传递参数
  3. 当我们注册事件时,event对象就会被系统自动创建,并依次传递给事件监听器(事件处理函数)通过事件来记录文件读取进度或异常行为
  4. 事件对象是我们事件的一系列相关数据的集合,跟事件相关的比如鼠标点击里面就包含了鼠标的相关信息,鼠标坐标等;如果是键盘事件里面就包含的键盘事件的信息,比如判断用户按下了哪个键等
  5. 这个事件对象我们可以自己命名,比如 event、evt、e
  6. 事件对象也有兼容性问题 IE678 通过 window.event 兼容性的写法 e = e || window.event

2.2事件对象的常见属性和方法

事件对象属性方法说明
e.target返回触发事件的对象 标准
e.srcElement返回触发事件的对象 非标准 IE6-8使用
e.type返回事件的类型 比如 click、mouseover,不带 on
e.cancelBubble该属性阻止冒泡 非标准 IE6-8使用
e.returnValue该属性阻止默认事件(默认行为) 非标准 IE6-8使用 比如不让链接跳转
e.preventDefault()该方法阻止默认事件(默认行为) 标准 比如不让链接跳转
e.stopPropagation()该方法阻止冒泡 标准

2.2.1 e.target 和 this 的区别

区别:e.target 点击了哪个元素,就返回哪个元素;this 哪个元素绑定了这个点击事件,那么就返回谁

// 常见事件对象的属性和方法

// 1 e.target 返回的是触发事件的对象(元素);this 返回的是绑定事件的对象(元素)
var div = document.querySelector('div');
div.addEventListener('click', function(e) {
    console.log(e.target); //<div>123</div>
    console.log(this); //<div>123</div>
})

var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
    // e.target 指向我们点击的那个对象 谁触发了这个事件 我们点击的是 li  e.target指向的就是li
    console.log(e.target); //点击的那一个 li
    // 我们给ul绑定了事件 那么 this 就指向 ul
    console.log(this); //ul 包括里面的li
    console.log(e.currentTarget); //跟 this 有个非常相似的属性 e.currentTarget (了解)  缺点:兼容性问题 IE678不认识
})
​
// 兼容性处理(了解)
div.onclick = function(e) {
    e = e || window.event;
    var target = e.target || e.srcElement;
    console.log(target);
}

2.2.2返回事件类型

// 返回事件类型
var div = document.querySelector('div');
div.addEventListener('clcik', fn);
div.addEventListener('mouseover', fn);
div.addEventListener('mouseout', fn);
​
function fn(e) {
    console.log(e.type);
}

2.2.3阻止默认行为

 // 阻止默认行为(事件) 让链接不跳转 或者让提交按钮不提交
 
 var a = document.querySelector('a');
 a.addEventListener('click', function(e) {
         e.preventDefault(); //dom 标准写法
     })
     // 传统的注册方式
 a.onclick = function(e) {
     // 普通浏览器支持 e.preventDefault(); 方法
     e.preventDefault();
     // 低版本浏览器 IE678 可以使用 returnValue 属性
     e.returnValue;
​
     // 可以利用 return false 也能阻止默认行为 没有兼容性问题 特点:return后面的代码不执行了,而且只限于传统的注册方式
     return false;
 }

2.2.4阻止事件冒泡的两种方式(重要)

事件冒泡:开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点

// son -> father ->body -> html -> document
var son = document.querySelector('.son');
son.addEventListener('click', function() {
    alert('son');
    e.stopPropagation(); //stop 停止   propagation 传播
    //e.cancelBubble = true;//cancel 取消  bubble 泡泡 冒泡 IE678支持
}, false);// 冒泡
var father = document.querySelector('.father');
father.addEventListener('click', function() {
    alert('father');
    e.stopPropagation(); 
}, false);

document.addEventListener('click', function() {
    alert('document'); // son->father->document
})
​
//阻止事件冒泡的兼容性解决方案
if (e && e.stopPropagation) {
    e.stopPropagation();
} else {
    window.event.cancelBubble = true;
}