JS的事件处理机制和事件委托

目录

一、DOM事件流

1.1 什么是DOM事件流

二、事件处理程序

2.1 最老的html事件处理程序

2.2 DOM0级事件处理程序

2.3 DOM2级事件处理程序

2.4 IE事件处理程序

2.5 跨浏览器的事件处理程序

三、事件对象

四、事件委托

4.1 什么是事件委托

4.2 事件委托有什么好处


一、DOM事件流

1.1 什么是DOM事件流

   当在html元素中发生了一个事件,事件会在目标节点与根节点之间按照特定的顺序传播,沿途的所有节点都会接收到该事件,这个传播过程成为DOM事件流。

  事件传播顺序:事件捕捉和事件冒泡

  事件捕捉:从DOM树最顶层的元素传递到最准确的元素,由外向内

  事件冒泡:从最确定的元素传递到最不确定的元素

 DOM2级事件规定DOM事件流包括事件捕捉阶段、目标阶段和冒泡阶段

  由上图可知当事件发生时,先进行事件捕捉阶段从window一直传递到具体事件发生标签,然后是目标阶段,执行对应的目标监听器,冒泡阶段就是从具体节点一直向上传递,直到window。所有的事件都会经历捕捉和目标阶段,但有些事件不会经历冒泡阶段,如:使鼠标聚焦的focus和失去焦点的blur事件。

二、事件处理程序

  事件处理程序就是相应某个事件而执行的函数,一般以on开头,如onclick,onkeyup,而click,

keyup称为事件

2.1 最老的html事件处理程序

   直接在html标签内监听事件的发生,默认是冒泡阶段执行,只能给元素绑定一个事件,this指向当前元素

<input type="button" value="click" οnclick="alert('clicked')"/>

2.2 DOM0级事件处理程序

  先获取标签,再绑定相应事件,默认是冒泡阶段执行,只能给元素绑定一个事件,this指向当前元素

    var item1 = document.getElementById("goSomewhere");
    var item3 = document.getElementById("sayHi");
 
    item1.onclick = function() {
      location.href = "http://www.baidu.com";
    };
    
    item3.onclick = function() {
      alert("hi");
    };

2.3 DOM2级事件处理程序

  可以为相同标签同时绑定多个事件,事件发生的顺序按照绑定的顺序(IE中相反),通过addEventListener()和removeEventListener()两个函数来定义。

  addEventListener(p1,p2,p3):p1:事件名称,p2:事件处理函数,p3:布尔值

  布尔值默认为false,表示在事件冒泡阶段执行

 通过addEventListener()添加的事件,之后一定要通过removeEventListener()去除,而且传入的参数也要一模一样。

var btn2 = document.getElementById('btn2');
var handlers = function () {
   console.log(this.id);
 };
btn2.addEventListener('click',handlers,false);
btn2.addEventListener("click",function(){alert("hello")},false);
btn2.removeEventListener('click',handlers.false);

2.4 IE事件处理程序

  在IE浏览器中通过attachEvent()和detachEvent()两个事件来定义,接受两个参数,第一个是on+事件名称,第二个是事件处理函数,IE浏览器中采用冒泡阶段执行的机制,this指向window对象,且可以同时绑定多个事件,事件发生顺序与DOM2级相反。

 var btn3 = document.getElementById('btn3');
 var handlers2=function(){
  console.log(this===window);//true,注意attachEvent()添加的事件处理程序运行在全局作用域中;
 };
 btn3.attachEvent('onclick',handlers2);

2.5 跨浏览器的事件处理程序

  实际开发中需要兼容不同浏览器,就有了以下写法:

 定义一个EventUtil对象,向里面添加不同的方法

const EventUtil = {
//添加事件监听,接受三个参数(绑定事件的元素,事件名,事件处理函数)
    addHandler: function(element,type,handler){
        if(element.addEventListener){             //DOM2级
            element.addEventListener(type,handler,false)
        }else if(element.attachEvent){            //IE浏览器
            element.attachEvent("on"+type,handler)
        }else{                                    //其他情况
            element["on"+type] = handler
        }

//去除事件监听
    removeHandler: function(element,type,handler){
        if(element.addEventListener){             //DOM2级
            element.removeEventListener(type,handler,false)
        }else if(element.attachEvent){            //IE浏览器
            element.detachEvent("on"+type,handler)
        }else{                                    //其他情况
            element["on"+type] = null
        }
}
            

三、事件对象

  每次在触发事件时,都会产生一个event对象,它包含了事件的大部分信息,如事件发生的类型和发生事件的元素。IE浏览器和其他浏览器不同,event对象是作为window的一个是属性存在,而其他浏览器直接以event对象存在。

  事件触发时会默认给事件处理程序传入一个event对象

其他浏览器event对象属性:

currentTarget只读事件处理程序当前正在处理事件的那个元素
datail只读与事件相关的细节
eventPhase只读调用事件处理程序的阶段1 捕获阶段 2  处于目标 3 冒泡阶段
target只读事件的目标
type只读被触发的事件的类型

IE浏览器event对象属性:

srcElement只读事件的目标(与DOM中target属性相同)
 
type 只读被触发的事件的类型
cancelBubble读/写默认值为false默认为true,设置为true可以取消事件冒泡(与DOM中stopPropagation()一样)
returnValue读/写  设置为false,就可以阻止默认行为。(与DOM中的preventDefault()一样)

跨浏览器的事件对象

const EventUtil = {
//添加事件对象
    getEvent: function(event){
        return event ? event || window.event
    }

//添加事件目标元素
    getTarget: function(event){
        return target ? event.target || event.srcElement
    }

//取消冒泡
    stopPropagation: function(event){
        if(event.stopPropagation){
            event.stopPropagation()
        }else if(event.cancelBuble){
            event.cancelBuble = true
        }
    }

//取消默认事件
    preventDefault: function(event){
        if(event.preventDefault){
            event.preventDefault()
        }else if(event.returnValue){
            event.returnValue = false
    }
}

    IE浏览器:window.event.cancelBuble  = true                取消冒泡

                      window.event.returnValue = false                 取消默认事件

    其他浏览器:event.stopPropagation()                            取消冒泡

                          event.preventDefault()                               取消默认事件

    vue中取消事件冒泡,捕捉

  • @click.stop : 阻止事件冒泡
  • @click.prevent : 阻止事件默认行为
  • @click.self : 事件只作用在元素本身,而不是其子元素

四、事件委托

4.1 什么是事件委托

  事件委托就是利用事件冒泡或捕捉的原理,将子元素的事件处理程序写到父元素中,利用事件委托,可以监听一系列的事件处理函数。

小栗子:

<ul id="ul1">
    <li>111</li>
    <li>222</li>
    <li>333</li>
    <li>444</li>
</ul>

  给每个小li都绑上事件处理函数

window.onload = function(){
    var oUl = document.getElementById("ul1");
    var aLi = oUl.getElementsByTagName('li');        //返回类数组对象
    for(var i=0;i<aLi.length;i++){
        aLi[i].onclick = function(){
            alert(123);
        }
    }
}

利用事件委托

window.onload = function(){
    var oUl = document.getElementById("ul1");
   oUl.onclick = function(){
        alert(123);
    }
}

  小li发生点击事件,冒泡到ul,执行ul元素的事件处理函数,这样每一个li发生点击,ul都能监听到。但这样有一个坏处,如果ul里还包含其他函数,而我只需要点击li发生alert事件,上面做法就不行了。

window.onload = function(){
  var oUl = document.getElementById("ul1");
  oUl.onclick = function(ev){
    var ev = ev || window.event;
    var target = ev.target || ev.srcElement;
    if(target.nodeName.toLowerCase() == 'li'){        //判断发生事件节点的名称
         alert(123);
         alert(target.innerHTML);
    }
  }
}

4.2 事件委托有什么好处

 事件委托可以减少事件绑定的次数,让代码更简洁,大大减小DOM的操作

 后增加的节点也会自动绑定事件监听,不用手动再绑定


    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值