当前位置: 澳门新濠3559 > 服务器运维 > 正文

响应某个事件的方法就叫做事件处理程序或者事

时间:2019-12-08 19:30来源:服务器运维
本文为大家详细分析了JS绑定事件,供大家参考,具体内容如下 题目1: DOM0 事件和DOM2级在事件监听使用方式上有什么区别? 一.事件 事件是用户或浏览器自身执行的某种动作,这是我

本文为大家详细分析了JS绑定事件,供大家参考,具体内容如下

题目1: DOM0 事件和DOM2级在事件监听使用方式上有什么区别?

一.事件

事件是用户或浏览器自身执行的某种动作,这是我自己的理解。


绑定事件有兼容性问题,在IE早期版本中使用的是obj.attachEvent(),而其他浏览器使用的则是addEventListener()。这两个方法都有三个参数,分别为:事件类型,事件函数,最后一个是布尔值,true或者是false。true表示在事件捕获阶段执行,false表示在事件冒泡阶段执行。 由于IE只支持事件冒泡,所以同大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段,即默认为”false” 这样可以最大限度地兼容各种浏览器。 最好只在需要在是事件到达目标之前截获它的时候将事件处理程序添加到捕获阶段。 如果不是特别需要,不建议在事件捕获阶段注册事件处理程序。 兼容各浏览器的事件绑定:

事件处理程序

我们也称之为事件侦听器(listener),事件就是用户或浏览器自身执行的某种动作。比如click、load、mouseover等,都是事件类型(俗称事件名称),而响应某个事件的方法就叫做事件处理程序或者事件监听器
也就是我们需要提前定义好某些事件发生了该怎么处理,这个过程叫做绑定事件处理程序

二.事件流

事件流描述的是从页面中接收事件的顺序,也可理解为事件在页面中传播的顺序。

 function addEvent(obj, eventType, callback, bubble){ if{ obj.addEventListener(eventType, callback, bubble); }else{ obj.attachEvent(eventType, callback, bubble); } }

DOM0级事件处理元素

DOM0级方法指定的事件处理程序被认为是元素的方法,就是将一个函数赋值给一个事件处理程序属性(每个元素包括window和document都有自己处理程序的属性)。例如:onclick、onmouseover、onmouseout等。因此,这时候的事件处理程序是在元素的作用域中执行的;例如DOM0级绑定事件的方法:

<body>
    <div id="div1">点我</div>
</body>
<script type="text/javascript">
    var btn = document.getElementById('div1');
    btn.onclick = function(event){
        console.log(event);
        console.log(this.id); //div1
        console.log(this.innerHTML);//点我
    }
  btn.onclick = null  // 删除事件
</script>

区别:DOM0级后面绑定的事件会覆盖前面绑定的事件,点击的时候会执行新绑定的

1.两种事件流模型

冒泡型事件流:事件的传播从DOM树的叶子到根。【推荐】——event bubbling
捕获型事件流:事件的传播葱DOM树的根到叶子。 ——event capturing

澳门新濠3559 1

两种事件流模型.png

调用时,注意callback函数不需要加括号,与setTimeout类似。

DOM2级事件处理元素

DOM2级事件定义了两个方法用于处理指定和删除事件处理程序的操作:

  • addEventListener
  • removeEventListener

所有的DOM节点都包含这两个方法,并且它们都接受三个参数:

  • 第一个参数是事件名(如click);
  • 第二个参数是事件处理程序函数;
  • 第三个参数如果是true则表示在捕获阶段调用,为false表示在冒泡阶段调用。
<input id="btnClick" type="button" value="Click Here" />

<script type="text/javascript">
    var btnClick = document.getElementById('btnClick');

    var handler=function() {
        alert(this.id);
    }

    btnClick.addEventListener('click', handler, false); //添加事件
    btnClick.removeEventListener('click', handler, false); //删除事件
</script>

addEventListener():可以为元素添加多个事件处理程序,触发时会按照添加顺序依次调用。
removeEventListener():不能移除匿名添加的函数。

区别:DOM2级不会覆盖前面绑定的事件,点击的时候所有绑定的事件会依次执行一遍

2.W3C标准模型

W3C标准采用捕获+冒泡。两种事件流都会触发DOM的所有对象,从document对象开始,也在document对象结束。

澳门新濠3559 2

W3C标准模型.png

W3C标准则取其折中方案. W3C事件模型中发生的任何事件, 先(从其祖先元素window)开始一路向下捕获, 直到达到目标元素, 其后再次从目标元素开始冒泡.
而你作为开发者, 可以决定事件处理器是注册在捕获或者是冒泡阶段. 如果addEventListener的最后一个参数是true, 那么处理函数将在捕获阶段被触发; 否则(false), 会在冒泡阶段被触发.

这部分都比较容易理解,对于最后一个参数,相信很多人并不是非常理解,总之我还是需要写程序测试一下才真正弄通。

题目2: attachEvent与addEventListener的区别?

addEventListenerremoveEventListener是DOM2级事件处理程序的两个方法,用于处理指定和删除事件处理程序的操作
attachEventdetachEvent是因为兼容IE浏览器(IE不支持addEventListenerremoveEventListener方法)而实现的(只有两个参数的)类似方法。

3.浏览器兼容问题

一些标准的浏览器中,如Chrome、Firefox等,支持这两种方式。而事实上,准确的说,是这两种方式的混合方式。
在低版本IE及Opera下,是不支持事件捕获的。而这个特点最明显体现在事件绑定函数上。
IE、Opera的事件绑定函数是attachEvent,而Chrome等浏览器则是addEventListener,而后者比前者的参数多了一个,这个参数是一个布尔值。这个布尔值由用户决定,用户若设为true,则该绑定事件以事件捕获的形式参与,若为false则以事件冒泡的形势参与。


   Document       最里面的    

 var out = document.getElementById; var middle = document.getElementById; var inner = document.getElementById; //&#28857;&#20987;inner&#26102;&#65292;&#35302;&#21457;&#39034;&#24207;&#20026;&#65306;inner-------middle------out out.addEventListener{alert; middle.addEventListener{alert; inner.addEventListener{alert; 

 var out = document.getElementById; var middle = document.getElementById; var inner = document.getElementById; //&#28857;&#20987;inner&#26102;&#65292;&#35302;&#21457;&#39034;&#24207;&#20026;&#65306;out------inner-------middle out.addEventListener{alert; middle.addEventListener{alert; inner.addEventListener{alert; 

 var out = document.getElementById; var middle = document.getElementById; var inner = document.getElementById; //&#28857;&#20987;inner&#26102;&#65292;&#35302;&#21457;&#39034;&#24207;&#20026;&#65306;out------inner-------middle out.addEventListener{alert; middle.addEventListener{alert; inner.addEventListener{alert;

 var out = document.getElementById; var middle = document.getElementById; var inner = document.getElementById; //&#28857;&#20987;inner&#26102;&#65292;&#35302;&#21457;&#39034;&#24207;&#20026;&#65306;out-------middle------inner out.addEventListener{alert; middle.addEventListener{alert; inner.addEventListener{alert;

 var out = document.getElementById; var middle = document.getElementById; var inner = document.getElementById; //&#28857;&#20987;inner&#26102;&#65292;&#35302;&#21457;&#39034;&#24207;&#20026;&#65306;middle-------inner------out out.addEventListener{alert; middle.addEventListener{alert; inner.addEventListener{alert;

 var out = document.getElementById; var middle = document.getElementById; var inner = document.getElementById; //&#28857;&#20987;inner&#26102;&#65292;&#35302;&#21457;&#39034;&#24207;&#20026;&#65306;out-------inner------middle out.addEventListener{alert; middle.addEventListener{alert; inner.addEventListener{alert;

区别:

  • 参数个数不相同,这个最直观,addEventListener三个参数attachEvent只有两个attachEvent添加的事件处理程序只能发生在冒泡阶段addEventListener**第三个参数可以决定添加的事件处理程序是在捕获阶段还是冒泡阶段处理**(我们一般为了浏览器兼容性都设置为冒泡阶段)

  • 第一个参数意义不同addEventListener第一个参数是事件类型(比如click,load),而attachEvent第一个参数指明的是事件处理函数名称(onclick,onload)

  • 事件处理程序的作用域不相同addEventListener的作用域是元素本身,this是指的触发元素,而attachEvent事件处理程序会在全局变量内运行this是window,所以会返回undefined,而不是元素

  • 为一个事件添加多个事件处理程序时,执行顺序不同addEventListener添加会按照添加顺序执行,而attachEvent添加多个事件处理程序时顺序无规律(添加的方法少的时候大多是按添加顺序的反顺序执行的,但是添加的多了就无规律了),所以添加多个的时候,不依赖执行顺序的还好,若是依赖于函数执行顺序,最好自己处理,不要指望浏览器

三.事件绑定与解绑

看完以上六种情况对应的结果,相信您已经能够深刻理解,最后一个参数为true或false的区别了。

题目3: 解释IE事件冒泡和DOM2事件传播机制?

事件流描述的是从页面中接收事件的顺序,目前主要有三种模型:

  • IE的事件冒泡:事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的元素

  • Netscape的事件捕获:不太具体的节点更早接收事件,而最具体的元素最后接收事件,和事件冒泡相反

  • DOM事件流:DOM2级事件规定事件流包括三个阶段,事件捕获阶段,处于目标阶段,事件冒泡阶段,首先发生的是事件捕获,为截取事件提供机会,然后是实际目标接收事件,最后是冒泡阶段

Opera、Firefox、Chrome、Safari都支持DOM事件流;
IE不支持事件流,只支持事件冒泡

澳门新濠3559 3

注意:DOM2级事件方法,addEventListener和removeEventListener第三个参数默认为false,所以在冒泡阶段触发,如果为true表示在捕获阶段调用事件处理程序。

1.直接在HTML中事件处理(不推荐)

<input type="button" value="showClick" onclick="showClick()" />

这种方法的有很多缺点:
(1)首先,存在一个时差问题。因为用户如果会在 HTML 元素一出现在页面上就触发相应的事件,但当时的事件处理程序有可能尚不具备执行条件。假如用户在页面解析事件处理函数之前就触发事件,就会引发错误。为此,很多HTML事件处理程序都会被封装在一个 try-catch 块中,这样错误不会浮出水面,因为在浏览器有机会处理错误之前,错误就被捕获了。如下面的例子所示:
<input type="button" value="showClick" onclick="try{showClick();}catch(ex){}">
(2)这样扩展事件处理程序的作用域链在不同浏览器中会导致不同结果。不同 JavaScript 引擎遵循的标识符解析规则略有差异,很可能会在访问非限定对象成员时出错。
(3)HTML 与 JavaScript 代码紧密耦合。如果要更换事件处理程序,就要改动两个地方:HTML 代码和 JavaScript 代码。而这正是许多开发人员摒弃 HTML 事件处理程序,转而使用 JavaScript 指定事件处理程序的原因所在。

题目4:如何阻止事件冒泡? 如何阻止默认事件?

  • DOM
    • 阻止事件冒泡e.stopPropagation()
    • 阻止默认事件event.preventDefault()
  • IE
    • 阻止事件冒泡e.cancelBubble = true
    • 阻止默认事件event.returnValue = false
2. 直接在dom对象上注册事件名称,就是DOM0写法,所有浏览器支持
//事件绑定
document.getElementById("patty").onclick = function(e){};/
document.getElementById("patty")["onmousemover"] = function(e){};

//事件解绑
document.getElementById("patty")["onmousemover"] = null;

//阻止默认事件(默认事件行为:href=""链接,submit表单提交等)
document.getElementById("patty").onclick = function() {
    ……                         //你的代码
    return false;              //通过返回false值阻止默认事件行为
};

在这里我觉得有必要解释两点
澳门新濠3559,(1)事件绑定通过.和[]的两种方式访问js对象属性的方法,[]的形式主要是为了解决属性名不是合法的标识符,比如:object.123肯定报错,但是object["123"]就避免了这个问题,与此同时,[]的写法,更加灵活,用字符串表示属性名称,可以在运行时动态绑定事件。
(2)return false 的含义不是阻止事件继续向顶层元素传播,而是阻止浏览器对事件的默认处理。 return false 只在当前函数有效,不会影响其他外部函数的执行。
总结
retrun true; 返回正确的处理结果。
return false;返回错误的处理结果,终止处理;阻止提交表单;阻止执行默认的行为。
return;把控制权返回给页面。

题目5:有如下代码,要求当点击每一个元素li时控制台展示该元素的文本内容。不考虑兼容

<ul class="ct">
    <li>这里是</li>
    <li>饥人谷</li>
    <li>前端6班</li>
</ul>
<script>
  var liNodes = document.querySelectorAll('.ct li');
  liNodes.forEach(function(node){
    node.addEventListener('click',function(){
      console.log(this.innerText)
    })
  })
</script>

代码

3.DOM2事件模型

· DOM2支持同一dom元素注册多个同种事件。
· DOM2新增了捕获和冒泡的概念。

题目6: 补全代码,要求:当点击按钮开头添加时在<li>这里是</li>元素前添加一个新元素,内容为用户输入的非空字符串;当点击结尾添加时在最后一个 li 元素后添加用户输入的非空字符串.

当点击每一个元素li时控制台展示该元素的文本内容。

<ul class="ct">
    <li>这里是</li>
    <li>饥人谷</li>
    <li>任务班</li>
</ul>
<input class="ipt-add-content" placeholder="添加内容"/>
<button id="btn-add-start">开头添加</button>
<button id="btn-add-end">结尾添加</button>
<script>
  var addStart = document.querySelector('#btn-add-start');
  var addEnd = document.querySelector('#btn-add-end');
  var addContent = document.querySelector('.ipt-add-content');
  var ct = document.querySelector('.ct');

  addStart.addEventListener('click',function(){
    if ( !/^s*$/.test(addContent.value) ){
      var node = document.createElement('li');
      node.innerText = addContent.value;
      ct.insertBefore(node,ct.firstChild);
  }})
  addEnd.addEventListener('click',function(){
    if ( !/^s*$/.test(addContent.value) ){
      var node = document.createElement('li');
      node.innerText = addContent.value;
      ct.appendChild(node);}
  })
</script>

代码

(1)addEventListener(event.type, handle, boolean); IE8及以下不支持

事件类型没有on,第三个参数false 表示在事件第三阶段(冒泡)触发,true表示在事件第一阶段(捕获)触发。 如果handle是同一个方法,只执行一次。

var element=document.getElementById("patty");
var handler=function(){ }
//绑定事件
element.addEventListener('click', handler, false);  
//解绑事件
element.removeEventListener('click', handle, false);
//阻止默认事件
element.addEventListener("click", function(e){
    var event = e || window.event;
    ……
    event.preventDefault( );      //阻止默认事件
},false);

题目7: 补全代码,要求:当鼠标放置在li元素上,会在img-preview里展示当前li元素的data-img对应的图片。

<ul class="ct">
    <li data-img="1.png">鼠标放置查看图片1</li>
    <li data-img="2.png">鼠标放置查看图片2</li>
    <li data-img="3.png">鼠标放置查看图片3</li>
</ul>
<div class="img-preview"></div>
<script>
  var ct = document.querySelector('.ct');
  var liNodes = document.querySelectorAll('.ct li');
  var imgPreview = document.querySelector('.img-preview');

  for(var i=0;i<liNodes.length;i++){
    liNodes[i].addEventListener('mouseover',function(){
    var dataImg = this.getAttribute('data-img');
    imgPreview.innerHTML = '![](' + dataImg + ')'
  })
  }
</script>

代码

(2)attachEvent(event.type, handle ); IE特有,兼容IE8及以下,可添加多个事件处理程序,只支持冒泡阶段,并不属于DOM2

如果handle是同一个方法,绑定几次执行几次,这点和addEventListener不同。事件类型要加on,例如onclick而不是click

参考文章

  • DOM0级和DOM2级事件处理程序的区别?
  • JS中dom0级事件dom0级和dom2级的区别事件的区别介绍
  • 关于DOM和事件的几个整理
  • 事件
特别注意:

在 IE 中使用 attachEvent() 与DOM0和DOM2addEventListener有一主要区别:事件处理程序的作用域。在这些方法中,事件处理程序会在其所属元素的作用域内运行;在使用 attachEvent() 方法的情况下,事件处理程序会在全局作用域中运行,因此 this 等于 window。

var element=document.getElementById("patty");
var handler=function(){ }
/绑定事件
element.attachEvent('onclick', handler); 
//解绑事件,参数和绑定一样
element.detachEvent("onclick", handler);
//阻止默认事件
element.attachEvent("onclick", function(e){
    var event = e || window.event;
    ……
    event.returnValue = false;       //阻止默认事件
},false);
(3)封装事件绑定与解绑函数,兼容浏览器
// 事件绑定
function addEvent(element, eType, handler, bol) {
    if(element.addEventListener){           //如果支持addEventListener
        element.addEventListener(eType, handler bol);
    }else if(element.attachEvent){          //如果支持attachEvent
        element.attachEvent("on"+eType, handler);
    }else{                                  //否则使用兼容的onclick绑定
        element["on"+eType] = handle;
    }
}

// 事件解绑
function removeEvent(element, eType, handler, bol) {
    if(element.addEventListener){
        element.removeEventListener(eType, handler, bol);
    }else if(element.attachEvent){
        element.detachEvent("on"+eType, handler);
    }else{
        element["on"+eType] = null;
    }
}

作为一个追求完美的人,我们可以将两个函数写成函数的方法模式

//用事件冒泡方式,如果想兼容事件捕获只需要添加个bool参数
var EventUtil = {
    addHandler: function(element,type,handler) {
        if (element.addEventListener) {
            element.addEventListener(type,handler,false);
        }
        else if (element.attachEvent) {
            element.attachEvent('on'+type,handler);
        }
        else {
            element['on'+type] = handler;
        }
    },

    removeHandler: function(element,type,handler) {
        if (element.removeEventListener)
        {
            element.removeEventListener(type,handler,false);
        }
        else if(element.detachEvent) {
            element.detachEvent('on' +type,handler);
        }
        else {
            element['on'+type] = null;
        }
    }
}

//使用
var patty= document.getElementById("patty");
var handler = function(){
    console.log("Don't touch patty");
};
EventUtil.addHandler(patty, "click", handler);
EventUtil.removeHandler(patty, "click", handler);

四.终止事件冒泡

事件冒泡、事件捕获阻止:

event.stopPropagation( ); // 阻止事件的进一步传播,包括(冒泡,捕获),无参数 ,ie不支持
event.cancelBubble = true; // true 为阻止冒泡,也有浏览器不支持

方法1:利用event.stopPropagation( )和event.cancelBubble
    var patty=document.getElementById("patty").addEventListener("click",function(event){  
    var event = event||window.event;
      ……
     event.stopPropagation();  
     });  

这里提供一个阻止冒泡兼容性写法

function stopPropagation(event){
    event=window.event||event;
    if(event.stopPropagation){ 
      event.stopPropagation();
    }else{
     event.cancelBubble=true;
    }
}
//直接调用
document.getElementById("patty").addEventListener("click",function(event){  
    ......
    stopPropagation(event);
}
方法2:利用event.target和event.currentTarget,事件包含最初触发事件的节点引用 和 当前处理事件节点的引用,节点只处理自己触发的事件
document.getElementById("patty").addEventListener("click",function(event){  
    event=window.event||event;
    //IE没有event.target,有event.srcElement    
     var target = event.target||event.srcElement;
    if(target == event.currentTarget)  
       { 
          ……
       }  
    });  

方法一缺点:为了实现点击特定的元素显示对应的信息,方法一要求每个元素的子元素也必须终止事件的冒泡传递,即跟别的元素功能上强关联,这样的方法会很脆弱。
方法二缺点:方法二为每一个元素都增加了事件监听处理函数,事件的处理逻辑都很相似,即都有判断 if(target == event.currentTarget),这样存在了很大的代码冗余,现在是三个元素还好,当有10几个,上百个又该怎么办呢?

改进(利用事件委托)

让某个父节点统一处理事件,通过判断事件的发生地(即事件产生的节点),然后做出相应的处理
这里我们先了解下事件委托的概念

事件委托:

利用事件冒泡的特性,将里层的事件委托给外层事件,根据event对象的属性进行事件委托,改善性能。使用事件委托能够避免对特定的每个节点添加事件监听器;事件监听器是被添加到它们的父元素上。事件监听器会分析从子元素冒泡上来的事件,找到是哪个子元素的事件。

  window.onload = function() {  
      document.getElementById("box").addEventListener("click",eventPerformed,false);  
   }  
  function eventPerformed(event) {  
       var event = event||window.event;
       var target = e.target||e.srcElement;
      switch (target.id) {  
        case "div1":  
            alert("您好,我是div1。");  
            break;  
        case "div2":  
             alert("您好,我是div2。");  
            break;  
        }  
    } 

五.最后给大家送上一个跨浏览器的事件对象

var EventUtil={
    getEvent:function(event){
        return event||window.event;
    },
    getTarget:function(event){
        return event.target||event.srcElement;
    },
    preventDefault:function(){
        if(event.preventDefault){
            event.preventDefault();
        }else{
            event.returnValue=false;
        }
    },
    stopPropagation:function(){
        if(event.stopPropagation){
            event.stopPropagation();
        }else{
            event.cancelBubble=true;
        }
    },
    addHandler:function(element,type,handler){
        if(element.addEventListener){
            element.addEventListener(type,handler,false);
        }else if(element.attachEvent){
             element["e"+type]=function(){
              handler.call(element)
          }
            element.attachEvent("on"+type,element["e"+type]);
        }else{
            element["on"+type]=handler;
        }
    },
    removeHandler:function(element,type,handler){
        if(element.removeEventListener){
            element.removeEventListener(type,handler,false);
        }else if(element.detachEvent){
            element.detachEvent("on"+type,element["e"+type]);
            element["e"+type]=null;    
        }else{
            element["on"+type]=null;
        }
    }

  };


//使用
var patty=document.getElementById("patty");
var handler=function(event){
   var event=EventUtil.getEvent(event);
   var target=EventUtil.getTarget(event);
   alert(target.id);
   EventUtil.stopPropagation(event);
}
EventUtil.addHandler(patty,'click',handler);

好了,关于JS事件暂且先写这么多,欢迎大家指正博文中错误。谢谢观看!

编辑:服务器运维 本文来源:响应某个事件的方法就叫做事件处理程序或者事

关键词: