浏览器相关 - 浏览器事件模型

详解浏览器事件捕获,冒泡

浏览器事件模型中的过程主要分为三个阶段:捕获阶段、目标阶段、冒泡阶段

    
parent

child son 点我啊

    const parent = document.getElementById("parent");
    const child = document.getElementById("child");
    const son = document.getElementById("son");

    window.addEventListener("click", function (e) {
        // e.target.nodeName 指当前点击的元素, e.currentTarget.nodeName绑定监听事件的元素
        console.log("window 捕获", e.target.nodeName, e.currentTarget.nodeName);
    }, true);

    parent.addEventListener("click", function (e) {
        // e.stopPropagation();
        
        console.log("parent 捕获", e.target.nodeName, e.currentTarget.nodeName);
    }, true);

    child.addEventListener("click", function (e) {
        console.log("child 捕获", e.target.nodeName, e.currentTarget.nodeName);
    }, true);

    son.addEventListener("click", function (e) {
        console.log("son 捕获", e.target.nodeName, e.currentTarget.nodeName);
    }, true);

    window.addEventListener("click", function (e) {
        console.log("window 冒泡", e.target.nodeName, e.currentTarget.nodeName);
    }, false);

    parent.addEventListener("click", function (e) {
        console.log("parent 冒泡", e.target.nodeName, e.currentTarget.nodeName);
    }, false);

    child.addEventListener("click", function (e) {
        console.log("child 冒泡", e.target.nodeName, e.currentTarget.nodeName);
    }, false);

    son.addEventListener("click", function (e) {
        console.log("son 冒泡", e.target.nodeName, e.currentTarget.nodeName);
    }, false);

第三个参数

这里要注意addEventListener的第三个参数, 如果为true,就是代表在捕获阶段执行。如果为false,就是在冒泡阶段进行

阻止事件传播

  • e.stopPropagation()
    大家常听到的是阻止冒泡,实际上这个方法不止能阻止事件冒泡,还能阻止捕获阶段的传播
  • stopImmediatePropagation()
    如果有多个相同类型事件的事件监听函数绑定到同一个元素,当该类型的事件触发时,它们会按照被添加的顺序执行。如果其中某个监听函数执行了 event.stopImmediatePropagation() 方法,则当前元素剩下的监听函数将不会被执行。

场景设计:

先有一个页面,这个页面上有许多元素, div p button
每个元素上都有自己的click事件,都不相同;

现在来了一个新的需求,一个用户进入这个页面的时候,会有一个状态banned, window.banned.
true: 当前用户被封禁了,点击任何元素,都不执行现有click,而是提示被封禁了
false:不作任何操作。

    window.addEventListener("click", function (e) {
        if(window.banned){
            e.stopPropagation();
            alert('你被封禁了');
            return;
        }
        // ...
    }, true);

阻止默认行为

  • e.preventDefault()
    e.preventDefault()可以阻止事件的默认行为发生,默认行为是指:点击a标签就转跳到其他页面、拖拽一个图片到浏览器会自动打开、点击表单的提交按钮会提交表单等等,因为有的时候我们并不希望发生这些事情,所以需要阻止默认行为

兼容性

attachEvent——兼容:IE7、IE8; 不支持第三个参数来控制在哪个阶段发生,默认是绑定在冒泡阶段
addEventListener——兼容:firefox、chrome、IE、safari、opera;

// 兼容写法
class BomEvent{
    constructor(element){
        this.element = element;
    }

    addEvent(type, handler){
        if(this.element.addEventListener){
            this.element.addEventListener(type, handler, false);  // IE不支持捕获
        }else if(this.element.attachEvent){
            this.element.attachEvent(`on${type}`, handler)
        }else{
            this.element[`on${type}`] = handler;
        }
    }

    removeEvent(){
        if(this.element.removeEventListener){
            this.element.removeEventListener(type, handler, false);
        }else if(this.element.detachEvent){
            this.element.detachEvent(`on${type}`, handler)
        }else{
            this.element[`on${type}`] = null;
        }
    }
}

// 阻止事件传播
function StopPropagation(ev){
    if(ev.stopPropagation){
        ev.stopPropagation();  // W3C
    }else{
        ev.cancelBubble = true;  // IE
    }
}

// 阻止默认行为
function preventDefault(ev){
    if(ev.preventDefault){
        ev.preventDefault()
    }else{
        ev.returnValue = false;
    }
}

绑定事件的运用,以及封装一个多浏览器兼容的绑定事件函数

大家常见的一个面试题可能是ul + li,点击每个li alert对应的索引,这里就给大家来写一下看看

  • 先来给每个li绑定事件
  • 再来写一个事件委托的方式

      
    • 1
    • 2
    • 3
    • 4
      // const liList = document.getElementsByTagName("li");
      // for(let i = 0; i

你可能感兴趣的:(javascript)