事件||事件流||通用事件侦听器函数

本文详细介绍了事件流的概念,包括事件冒泡与事件捕获,并解释了如何在不同浏览器环境下使用DOM0级、DOM2级及IE事件处理程序。同时,提供了一个通用事件监听器函数的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

事件||事件流||通用事件侦听器函数

1、跨浏览器事件对象:

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

IE:的事件流是事件冒泡流。

事件冒泡(event bubbling):事件由最具体的元素(嵌套最深的那个节点)接收,然后逐级向上传播到不具体的节点(文档)。明显的缺点就是在多个子元素上绑定事件,父元素节点会接受到所有的事件绑定,这是个很坑爹的体验。

Netscape Communicator:的事件流是事件捕获流。

事件捕获(event capuring):是不太具体的元素节点应该更早的接收到事件,而更具体的节点应该最后接收到事件。符合常用的模型和思考方式。

Dom事件流:“Dom2级事件”规定了事件流包括三个阶段。(事件代理处理)

事件捕获阶段、处于事件阶段和事件冒泡阶段。即事件捕获为截获事件提供了机会,接着实际的目标接收到事件,最后冒泡阶段,在这个阶段对事件做出响应。

实际上这里已经显示了捕获要在冒泡之前。

大多的时候会把事件流添加到冒泡阶段,这样可以最大限度的兼容各种浏览器。此时DOM2级事件设为false。

这里的捕获阶段不涉及事件目标。这个时候的事件冒泡或者是事件捕获使用,添加事件最后的限定true(捕获阶段)||false(冒泡阶段)来触发。如果不写是根据浏览器的特性来实现的。

如下来验证:一个DOM元素绑定两个事件,一个冒泡,一个捕获,则事件会执行多少次,执行顺序如何。先捕获后冒泡。

//如下事件冒泡阶段触发
<div id='one'>1
  <div id='two'>2
    <div id='three'>3
      <div id='four'>4
      </div>
    </div>
  </div>
</div>
<script type='text/javascript'>
  var one=document.getElementById('one');
  var two=document.getElementById('two');
  var three=document.getElementById('three');
  var four=document.getElementById('four');
  one.addEventListener('click',function(){
    alert('one');
  },false);//表示在冒泡阶段触发事件
  two.addEventListener('click',function(){
    alert('two');
  },false);
  three.addEventListener('click',function(){
    alert('three');
  },false);
  four.addEventListener('click',function(){
    alert('four');
  },false);
</script>

//点击4,依次会触发four、three、two、one。
<div id='one'>1
  <div id='two'>2
    <div id='three'>3
      <div id='four'>4
      </div>
    </div>
  </div>
</div>
<script type='text/javascript'>
  var one=document.getElementById('one');
  var two=document.getElementById('two');
  var three=document.getElementById('three');
  var four=document.getElementById('four');
  one.addEventListener('click',function(){
    alert('one');
  },true);//表示在捕获阶段触发事件
  two.addEventListener('click',function(){
    alert('two');
  },true);
  three.addEventListener('click',function(){
    alert('three');
  },true);
  four.addEventListener('click',function(){
    alert('four');
  },true);
</script>
//点击4则依次触发:one、two、three、four
<div id='one'>1
  <div id='two'>2
    <div id='three'>3
      <div id='four'>4
      </div>
    </div>
  </div>
</div>
<script type='text/javascript'>
  var one=document.getElementById('one');
  var two=document.getElementById('two');
  var three=document.getElementById('three');
  var four=document.getElementById('four');
    one.addEventListener('click',function(){
      alert('one');
    },true);
    two.addEventListener('click',function(){
      alert('two,bubble');
    },false);//这里的事件在冒泡阶段触发
    two.addEventListener('click',function(){
      alert('two,capture');
    },true);//这里的事件在捕获阶段触发
    three.addEventListener('click',function(){
      alert('three,bubble');
    },true);
    four.addEventListener('click',function(){
      alert('four');
    },true);
</script>
<!-- 执行顺序最终结果是:(chrome先捕获后冒泡)点击4,依次会触发 one、two,capture、three,bubble、four、two,bubble-->
<!-- 说明,同一个元素上绑定事件是先捕获,再冒泡。中间还有一个处于目标阶段 -->

2、事件处理程序(事件侦听器):

事件是用户或浏览器自身执行的某种动作:如click、load、mouseover等,响应某个事件的函数称为事件处理程序(事件监听器)。

1、html事件处理程序

事件处理程序中的代码在执行时,有权访问全局作用域中的任何代码(匿名函数的作用域-全局)。

直接写在页面元素中,强耦合,摒弃。页面在前解析,js在后解析。

存在时差问题,可能在处理程序解析之前就触发了事件,会导致错误。

MouseEvent对象如下:

<input type="button" value = "click me" onclick = "console.log(event)"/>

这里的path保存着事件冒泡的顺序(具体到不具体),target保存着目标节点的信息,view保存着window对象的一些信息。

2、Dom0级事件处理程序(onclick): 

通过JavaScript指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。这种方法被称为事件处理程序赋值,出现在第四代 Web 浏览器中。

每个元素(包括 window 和 document)都有自己的事件处理程序属性,属性通常全部小写,如 onclick。将这种属性的值设置为一个函数,就可以指定事件处理程序。

<input type="button" value = "Dom0" id = "myBtn" />
<script type="text/javascript">
    var btn = document.getElementById("myBtn");
    btn.onclick = function(event){
        console.log(event);
    }
</script>

打印结果与上边无差。处理函数内部this指向元素节点。可以取到this.id。

删除事件,将事件处理函数置为null即可。

btn.onclick = null;

3、Dom2级事件处理程序(事件绑定与取消绑定):

“DOM2级事件”定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListener()和removeEventListener() ;

它们接受3个参数:

  1. 要处理的事件名

  2. 作为事件处理程序的函数

  3. 一个布尔值:

    true: 捕获阶段调用事件处理程序

    false: 冒泡阶段调用

<input type="button" value = "Dom2" id = "myBtn2" />
<script type="text/javascript">
    var btn = document.getElementById("myBtn2");
    btn.addEventListener("click",function(event){
        alert("Dom2");
        console.log(event);
    },false);
</script>

事件event与之前的无差。

可以添加多个事件,添加多个事件的时候,按添加的顺序依次执行。

移除事件要一一对应,注意由于匿名函数在内存中没有指向对象,所以添加之后无法移除,所以做好的做法就是先定义好声明的处理函数(或者函数表达式),在进行绑定和删除。

大部分时候都是把事件添加到冒泡(false)阶段,这样可以最大限度的兼容各种浏览器。

4、IE事件处理程序: 

IE 实现了与 DOM 中类似的两个方法:attachEvent()和detachEvent() 

接受两个参数:事件处理程序名称、事件处理程序函数 

通过这种方法添加的事件处理程序会被添加到冒泡阶段。 

<input type="button" value = "IE" id = "myBtn3" />
<script type="text/javascript">
    var btn = document.getElementById("myBtn3");
    btn.attachEvent("onclick",function(event){
        alert("Clicked");
        console.log(event);
        console.log(this)
    });
</script>

打印的结果不能展开:

在IE中使用 attachEvent() 与使用 DOM0 级方法的主要区别在于事件处理程序的作用域。

DOM0 级方法:在Dom0级事件当中,事件处理程序会在其所属的元素的作用于内运行。

attachEvent()方法:使用attachEvent()方法的情况下,事件处理程序会在全局作用域中运行。此时this 等于window。

当然,匿名函数不能被移除。

5、事件对象:

触发Dom上的某个事件的时候,会产生一个事件对象event,这个对象包含着与事件相关的信息,包含导致事件的元素、事件的类型及其他信息。

event对象包含着与创建它的特定事件有关的属性和方法。

Dom中的事件对象:

事件对象的一些属性和方法:

主要的有:

cancelable:表明是否可以取消事件默认行为。

currentTarget:时间处理程序当前正在处理的那个元素处理程序内部,对象this始终等于currentTarget的值。而target只包含事件的实际目标。

preventDefault():取消事件的默认行为

target:事件目标。

stopPropagation(): 取消事件进一步的捕获或者冒泡

只有在执行事件期间,event才存在,事件执行完成之后,event对象就会被销毁。

IE事件对象中有区别的地方:

3、通用事件监听函数

//写一个通用的事件侦听器函数
//跨浏览器事件对象
var EventUtil = {
    //页面加载完成之后,页面完全加载之后执行。
    readyEvent:function(fn){  
        if(document.addEventListener){      
            //标准浏览器  
            document.addEventListener('DOMContentLoaded',function(){  
                //注销事件,避免反复触发  
                document.removeEventListener('DOMContentLoaded',arguments.callee,false); 
                //执行函数   
                fn();
            },false);  
        }else if(document.attachEvent){     
            //IE浏览器  
            document.attachEvent('onreadystatechange',function(){  
                if(document.readyState=='complete'){  
                    document.detachEvent('onreadystatechange',arguments.callee);  
                    //执行函数   
                    fn();  
                }  
            });  
        }  
    },
    /*
     *attachEvent可以使用匿名函数,但这样之后,detachEvent将无法卸载之。
     *detachEvent所卸载的函数必须使用函数名。
     */
    //添加事件
    addEvent:function(element,type,handler){
        if(element.addEventListener){//非IE,DOM2
            //事件类型、需要执行的函数、是否捕获
            element.addEventListener(type,handler,false);
        }else if(element.attachEvent){//IE
            element.attachEvent('on'+type,handler);
        }else{
            element['on'+type] = handler;//DOM0
        }
    },
    //移除事件
    removeEvent:function(element,type,handler){
        if(element.removeEventListener){
            element.removeEventListener(type,handler,false);
        }else if(element.detachEvent){
            element.detach('on'+type,handler);
        }else{
            element['on'+type] = null;
        }
    },
    //阻止事件冒泡(主要是事件冒泡,因为IE不支持事件捕获),用于立即停止事件在Dom层中的传播,即进一步取消事件的捕获或者冒泡。
    stopPropagation:function(event){
        if(event.stopPropagation){
            event.stopPropagation();//W3C标准
        }else{
            event.canceBubble = true;//IE
        }
    },
    //取消事件的默认行为, 如url的跳转等
    preventDefault:function(event){
        if(event.preventDefault){
            event.preventDefault();//W3C标准
        }else{
            event.returnValue = false;//IE
        }
    },
    //获取事件目标
    getTarget:function(event){
        return event.target||event.srcElement;
    },
    //获取event对象的引用,获取事件的所有信息,确保随时能使用event;
    getEvent:function(event){
        var event = event||window.event;//在Dom0级事件添加,event作为window对象的一个属性存在。
    }
};
// 定义一个函数处理多种类型的事件
var handler = function(event){
    switch(event.type){
        case "click":
            alert("Clicked");
            break;
        case "mouseover":
            event.target.style.backgroundColor = "red";
            break;
        case "mouseout":
            event.target.style.backgroundColor = "";
            break;
        default:
            alert("test switch");
    }
};
//阻止事件冒泡的实例
var btnCancel = document.getElementById("btnCancel");
btnCancel.onclick = function(event){
    alert("clicked222");    
    //这样之后,body上的事件就不会触发了,不然点一下,就会触发这两个事件。
    EventUtil.stopPropagation(event);
};

document.body.onclick = function(event){
    //如果btnCancle上阻止了事件冒泡,那么body上的事件就不会被添加到btnCancle上。
    alert("body clicked")
}
获取一组元素的序号,原理是自己先要获取元素然后添加属性到标签中。点击事件的时候再获取自定义的属性。
两种方法,标签添加属性和使用自定义属性。
另:Dom0型事件的处理函数的this 等于 event.target属性。

<ul >
    <li class="a1">1</li>
    <li class="a2">2</li>
    <li class="a3">3</li>
    <li class="a4">4</li>
    <li class="a5">5</li>
    <li class="a6">6</li>
</ul>

var list = document.getElementsByTagName("li");
for(var i = 0,len = list.length;i<len;i++){
    list[i].index = i;//方法1,比较好
    list[i].setAttribute("data-index",i);//方法2
    list[i].onclick = function(event){
        console.log(this.getAttribute("data-index"));
        console.log(this.index);
        console.log(event);
        console.log(this==event.target);
    }
}

//当然事件也是可以绑定到父元素上
var ul = document.getElementsByTagName("ul");
ul[0].onclick = function(event){
    console.log(event.target.index);
}

IE事件与FF(DOM)事件的区别:

1、window.event

表示当前的事件对象,IE的事件对象是window对象的一个属性。 FF:没有window.event对象。可以通过给函数的参数传递event对象。如onmousemove=domousemove(event)。

2、获取事件源

IE:srcElement;FF:target;

3、添加删除事件方法不同

IE:element.attachEvent("onclick",function(){})

FF: element.addEventListener("click",function(){},false);

删除事件也是不同的。

4、自定义DOM事件

自定义DOM事件不是由DOM原生触发的,目的是让开发人员创建自己的事件。创建自定义事件,需要调用createEvent("CustomEvent");

且看如下实例:

var div = document.getElementById("myDiv");

var event;
EventUtil.addHandler(div,"myevent",function(event){
  alert("DIV:   " + event.detail);
});
EventUtil.addHandler(document,"myevent",function(event){
  alert("DOCUMENT:   " + event.detail);
});

if(document.implementation.hasFeature("CustomEvents","3.0")){
  event = document.createEvent("CustomEvent");
  event.initCustomEvent("myevent",true,false,"hello world!");//对应参数:触发事件类型、事件是否冒泡、事件是否可以取消、任意值,保留在event对象的detail中
  div.dispatchEvent(event);
}

事件代理:

事件代理,具体实例,上边的ul元素绑定index,可以用。

转载于:https://www.cnblogs.com/changyangzhe/p/5724185.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值