DOM事件2-事件对象和冒泡捕获等传播机制

228 阅读3分钟

事件对象

我们先来做一个实验

let n;
box.onclick = function (ev) {
	n = ev;
}
document.body.onclick = function (ev) {
    console.log(n === ev); //=>TRUE
};

由此可知:

当事件行为触发,浏览器会把绑定的方法执行,并且把全局下记录当前操作信息的“事件对象”传递给这个函数

当前做了某些操作,不管在哪一个函数中,我们获取的事件对象是同一个,存储的是当前操作的信息,和函数没关系

【事件对象】

【鼠标事件对象】 MouseEvent
   * clientX/clientY: 鼠标触发点距离当前窗口左上角的X/Y轴坐标
   * ageX/pageY: 鼠标触发点距离BODY(页面首屏)左上角的X/Y轴坐标
   * path: 存储的是冒泡阶段需要传播的路径(值是捕获阶段获取的)
   * srcElement/target: 事件源(当前操作的元素)
   * type: 事件类型
【键盘事件对象】 KeyboardEvent
   * which/keyCode:键盘按键的键盘码
   * shiftKey/altKy/ctrlKey: 记录是否在按键的时候,按下这些键(组合按键,属性值是布尔类型)
【常规事件对象】 Event
【手指事件对象】 TouchEvent
 ......
 
Event.prototype
 *  阻止事件的默认行为
 *  ev.preventDefault() / ev.returnValue=false
 *     
 *  阻止事件的冒泡传播
 *  ev.stopPropagation() / ev.cancelBubble=true
 
 document.onkeydown = function (ev) {
    let {ctrlKey,keyCode} = ev;
    // 按CTRL+F禁止默认行为,我们期望它刷新页面
    if (ctrlKey && keyCode === 70) {
        ev.preventDefault();
        location.href = location.href;
    }
};

document.oncontextmenu = function (ev) {
    //禁止右键菜单
    //ev.preventDefault();

    //return false; 这也是阻止默认行为
};

事件是具备传播机制

  • 捕获 CAPTURING_PHASE 1

  • 目标 AT_TARGET 2

  • 冒泡 BUBBLING_PHASE 3

  • 当我们触发当前元素的某个事件行为的时候:

  • 1.首先会从最外层window开始,一层层的按照结构向里层查找【捕获:为冒泡阶段提供传播的路径 => ev.path】

  • 2.找到当前的事件源,触发当前事件源的相关行为 【目标】

  • 3.不仅当前事件源的相关行为被触发,其所有祖先元素的相关事件行为都会被触发(在这个过程中,哪一个元素的事件行为绑定了方法,方法都会被触发执行,而且顺序是由里层向外层传播) 【冒泡】

    window.addEventListener('click', function () { console.log('WINDOW'); });

    document.addEventListener('click', function () { console.log('DOCUMENT'); });

    // HTML

    document.body.addEventListener('click', function () { console.log('BODY'); });

    outer.addEventListener('click', function () { console.log('OUTER'); });

    inner.addEventListener('click', function () { console.log('INNER'); });

大部分事件默认都会存在冒泡传播机制,但是少部分事件天生自己就阻止了冒泡传播

mouseenter/mouseleave

mouseover/mouseout

大部分人会认为,这两套事件是一样的,没什么区别,但其实如果涉及到冒泡就会发生不一样的事

我们还是拿上一个例子来说

inner.onmouseover = function () {
    console.log('INNER OVER');
};
inner.onmouseout = function () {
    console.log('INNER OUT');
};

让我从上往下划入的时候,子元素和父元素都触发了划入事件,没问题 然而当只是划出子元素时,父元素也跟着触发划出事件,这个就是因为mouseover/mouseout冒泡的机制,同时他还认为子元素和父元素是分开的,鼠标从子元素进入到父元素时,浏览器会认为是重新进入父元素

然而当我们使用mouseenter/mouseleave时就不会

outer.onmouseover = function () {
    console.log('OUTER OVER');
};
outer.onmouseout = function () {
    console.log('OUTER OUT');
};

使用mouseenter/mouseleave浏览器认为进出哪个元素就是哪个元素,也不会冒泡

所以我们可以总结