JavaScript之事件流与事件处理程序(事件)

事件

事件,就是文档与浏览器发生特定的 交互瞬间。JavaScript与HTML之间的交互就是通过事件实现的。

事件流

所谓事件流,就是接收页面事件的顺序。

事件流分 事件冒泡流事件捕获流。事件冒泡流是IE开发团队提出的,捕获流是Netscape开发团队提出的。

事件冒泡流

所谓事件冒泡,就是事件开始时由 最具体的元素(文档中嵌套最深的那个 节点)接收,然后逐级向上传播到较为不具体的节点(文档)

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
	<title>事件</title>
  </head>
  <body>
  
    <div id="div1"></div> // 具体的元素接收事件
  
  </body>
</html>


如例,事件开始时,由<div>这个具体的元素接收,然后逐级向上传播,分别传播至<body>、<html>,最后是document。document就是较为不具体的节点。也就是说,当我们单击时,事件由<div>开始向DOM树逐级传播,传播至DOM树上每一级节点,直至传播document对象。这就是冒泡事件流的过程。事件冒泡是个很实用的流派。



事件捕获流


事件捕获流与事件冒泡流是相反的过程,即,事件开始时,由document对象接收,然后在DOM树上逐级向下传播,最后传至<div>这个具体的节点。

还是建议使用事件冒泡流。



DOM事件流

DOM事件流分为三个阶段: 事件捕获段、处于目标阶段、事件冒泡段

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
	<title>事件</title>
  </head>
  <body>
  
    <div id="div1"></div> // 具体的元素接收事件
  
  </body>
</html>


事件开始,由document接收并在DOM树逐级向下传播,分别至<html>、<body>,当到<body>时就停止,此时进入目标阶段,于是事件在<div>上发生,并在事件处理中看成是冒泡的一部分,接下来就处于冒泡阶段了



事件处理程序


事件就是用户自身或浏览器自身的某个特定动作、行为。如:click、mouseover、load等都是事件的名字。而 响应这些事件的就是事件处理程序或叫事件侦听器,以"on"+事件名组成。事件处理程序都是以"on"开头的,如click事件就叫"onclick"、mouseover事件就叫"onmouseover"。为事件指定处理方式的方法有多种。


HTML事件处理程序

某个元素支持的多个事件,都可以用与事件处理程序同名的HTML特性指定,特性值就是要执行的JavaScript代码。
例如单击事件:
<div id="div1" value="单击事件" οnclick="alert('HTML事件处理程序');"></div>

单击这个按钮,会弹出一个警告框。这是通过onclick特性执行JavaScript代码来完成的。

除了直接将要执行的代码作为onclick特性的值来执行外,还可以用onclick特性调用页面其它地方的函数来完成。

<body>
  
  <div id="div1" value="单击事件" οnclick="showMess()"></div> 
  
  <script>
      function showMess () {
          alert("HTML事件处理程序");
      }
</script>
</body>

单击按钮,就会执行showMess()函数,这个函数单独在<script>中的,也可以在外部文件中。 事件处理程序在执行时,有权访问全局作用下的所有代码

这样做可以将要执行的事件封装到一个函数中,在创建这个 函数时,函数中会有一个局部变量即event。


使用HTML事件处理程序有两个缺点:

1、这样做可能会 时差问题,当用户发现HTML出现在页面上就点击按钮,这里事件可能不具备触发的条件。showMess()函数可能是在页面最底端定义的,当用户在页面解析showMess()函数之前就点击了按钮,这时JavaScript会报错。解决方法可以用 try-catch()封装,即:

<body>
  
  <div id="div1" value="单击事件" οnclick="try{showMess();}catch(ex){}"></div> 
  
  <script>
      function showMess () {
          alert("HTML事件处理程序");
      }
</script>
</body>


2、 HTML和JavaScript代码紧密耦合。这样的话,如果要更换事件处理程序,则需要更换两个地方:HTML和JavaScript。



DOM 0级事件处理程序

指定事件处理程序的传统方式,就是 将一个函数赋值 给一个事件处理程序属性

每个元素都有自己的事件处理程序属性,包括document和window。
<body>
  
  <input id="input1" type="button" value="单击事件">
  
  <script>

      var input1 = document.getElementById("input1");

      input1.onclick = function () {
          alert("DOM 0级事件处理程序");
      }
</script>
</body>

注意:这些代码执行之前是不会指定事件处理程序的,也就是说,如果指定事件处理程序的代码是在按钮之后,那么可能点击多次按钮都没有反应。

DOM 0级事件处理程序被认为是元素的方法,是在元素的作用域中完成的,所以可以通过this对象访问当前元素的所有属性和方法。

<body>
  
  <input id="input1" type="button" value="单击事件">
  
  <script>

      var input1 = document.getElementById("input1");

      input1.onclick = function () {
          alert(this.id); //input1
      }
</script>
</body>


除了可以指定事件处理程序外,还可以 删除事件处理程序。通过给事件处理程序属性赋值null可以达成
<body>
  
  <input id="input1" type="button" value="单击事件">
  
  <script>

      var input1 = document.getElementById("input1");

      input1.onclick = function () {
          alert(this.id); //input1
      }
      input1.onclick = null; //这样点出按钮就没反应了
</script>
</body>


注:HTML事件处理程序也可以通过赋值null删除程序。

通过将事件处理程序设置为null,可以将删除该事件处理程序,一般用于清除垃圾,减少内存占用率。这是提高性能的方法之一。



DOM 2级事件处理程序

DOM2级定义了两个方法,用于添加和删除事件处理程序: addEventListener()removeEventListener()。eventListener叫事件句柄又称事件监听器。这两个方法接收的参数一个,都接收三个参数。 第一参数是要添加的事件名,第二个参数是作为事件处理程序的函数,第三个参数是个布尔值,true表示事件捕获,false表示事件冒泡。一般设置为false。因为事件冒泡是所有浏览器都支持的。在特殊的情况下才用事件捕获。

注:第一个参数事件名需用双引号括起来。

就拿上个例子来说:
<body>
  
  <input id="input1" type="button" value="单击事件">
  
  <script>

      var input1 = document.getElementById("input1");

      input1.addEventListener("click", function () {
	      alert(this.id); //input1
	  }, false)
</script>
</body>

注:DOM2级事件处理程序也是在当前元素的作用域下完成的。因此this对象可以访问当前元素的所有属性和方法。


通过addEventListener()添加的事件只能通过removeEventListener()方法来删除。但这里要注意一点的是:第二个参数传入的是相同的函数名而非相同的函数。
<body>
  
  <input id="input1" type="button" value="单击事件">
  
  <script>

      var input1 = document.getElementById("input1");

      input1.addEventListener("click", function () {
	      alert(this.id); //input1
	  }, false)
      
      //这样是删除不了事件的
      input.removeEventListener("click", function () {
	      alert(this.id);
	  }, false)
</script>
</body>

当我们点击按钮时,还是会弹出"input1"来,这是因为看似我们为删除事件方法传入的第二个参数是与添加事件的方法的参数一样的。其实不然,这两个方法添加的第二个参数是两个不同的函数。是不同的Function实例。
解决这个问题的方法就是:将这个函数先赋值给一个变量,再传入这个变量即可。

<body>
  
  <input id="input1" type="button" value="单击事件">
  
  <script>

      var input1 = document.getElementById("input1");
      //将事件处理函数赋值给一个变量
      var event = function () {
	      alert(this.id);
	  };
      //并将这个变量传入添加事件函数和删除事件函数  
      input1.addEventListener("click", event, false);
	  
      input1.removeEventListener("click", event, false); //删除事件
</script>
</body>
这样就删除了事件,此时addEventListener和removeEventListener传入的第二个参数才是相同的。


IE中事件处理程序

IE提供了两个方法为页面添加事件处理程序:attachEvent()和detachEvent()方法。这两个方法接收两个相同的参数, 第一个参数为事件处理程序名称第二个参数为事件处理函数。

在IE浏览器下运行。
<body>
  
  <input id="input1" type="button" value="单击事件">
  
  <script>

      var input1 = document.getElementById("input1");

      var event = function () {
	      alert("IE事件处理程序");
	  };

	  
      input1.attachEvent("onclick", event); //IE事件处理程序
</script>
</body>
如果在其它浏览器下运行会报错,该方法只是支持IE浏览器的。


I E事件处理程序与DOM 0级事件处理程序的区别在于:DOM 0级事件处理程序在在 当前元素的作用域下运行的,即 this是指向当前元素的。而对于 IE事件处理程序来说,是在 全局作用域下运行的,即 this是指向window的。

<body>
  
  <input id="input1" type="button" value="单击事件">
  
  <script>

      var input1 = document.getElementById("input1");

      var event = function () {
	      alert(this == widonw); //true
	  };

	  
      input1.attachEvent("onclick", event); //true
</script>
</body>



通过attachEvent()添加的事件可以用detachEvent()来删除,同样的,这个两个函数的第二个参数也必须相同,即将函数赋值给一个变量,将这个变量作为传递的参数即可。

<body>
  
  <input id="input1" type="button" value="单击事件">
  
  <script>

      var input1 = document.getElementById("input1");

      var event = function () {
	      alert(this == widonw);
	  };

	  
      input1.attachEvent("onclick", event); 

      input1.detachEvent("onclick", event); //删除事件,点击按钮无反应。
</script>
</body>

运行代码后,再次点击按钮,就没有了反应。


注:IE添加的事件处理程序与DOM0方法添加的事件处理程序有一点不同:即在IE中,事件处理程序不是以添加的它们的顺序执行,而是以相反的顺序执行。如:
<body>
  <input id="inpt1" type="submit" value="提交">

  <script>
     var inpt1 = document.querySelector("#inpt1");
     
     inpt1.attachEvent("onclick", function () {
         console.log("我是第二个执行的!!!");
     });
     inpt1.attachEvent("onclick", function () {
         console.log("我是第一个执行的!!!");
     });
 </script>
</body>

效果:



可以看出,在在IE中的事件处理程序不是以添加它们的顺序执行的,而是以相反的顺序执行的。



跨浏览器的事件处理程序


相要解决跨浏览器的问题,只需在必要时进行能力检测即可。

首先要创建一个addHandler()方法,它的作用就是视情况使用addEventListener()、attachEvent()或DOM 0级事件处理程序。这个方法属性EventUtil对象。也就是将添加事件句柄与删除事件句柄的方法封装于一个对象的属性中。使用该对象调用这个属性就可以为元素对象添加事件与删除事件了

addHandler()方法接收三个参数:要操作的元素、事件名称和事件处理函数。

首先创建EvnetUtil对象:

var EventUtil = {
    //这是添加事件句柄
    addHandler : function (element, type, handler) {
		  
        //DOM 2级事件处理程序  
        if (element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) { // IE事件处理程序
            element.attachEvent("on" + type, handler); //在IE中,需要"no" + 事件名
        } else {
            
            //将当前元素看作对象,引用事件处理程序这个属性,即<div οnclick="handler">
            element["on" + type] = handler; // DOM 0级事件处理程序
        }
    },
		  
    //这是删除事件句柄
    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; //DOM 0级删除事件赋值null给事件处理程序名即可。
        }
    }
};



为元素对象添加事件:EventUtil对象调用addHandler()方法为元素添加事件,此时,事件名需用双引号括起来。
var input1 = document.getElementById("input1");

//将事件函数赋值给一个变量,便于添加事件方法与删除事件方法传入的参数相同。
var event = function () {
    alert( "hi");
};

//将添加事件方法和删除事件封装在一个对象中
var EventUtil = {
    //这是添加事件
    addHandler : function (element, type, handler) {
		  
        //DOM 2级事件处理程序  
        if (element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) { // IE事件处理程序
            element.attachEvent("on" + type, handler);
        } else {
            
            //将当前元素看作对象,引用事件处理程序这个属性
            element["on" + type] = handler; // DOM 0级事件处理程序
        }
    },
		  
    //这是删除事件
    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; //DOM 0级删除事件赋值null给事件处理程序名即可。
        }
    }
};

EventUtil.addHandler(input1, "click", event); //hi   添加事件处理程序




为元素对象删除事件:EventUtil对象调用removeHandler()方法删除事件。
var input1 = document.getElementById("input1");

//将事件函数赋值给一个变量,便于添加事件方法与删除事件方法传入的参数相同。
var event = function () {
    alert(this == widonw);
};


var EventUtil = {
    //这是添加事件
    addHandler : function (element, type, handler) {
		  
        //DOM 2级事件处理程序  
        if (element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) { // IE事件处理程序
            element.attachEvent("on" + type, handler);
        } else {
            
            //将当前元素看作对象,引用事件处理程序这个属性
            element["on" + type] = handler; // DOM 0级事件处理程序
        }
    },
		  
    //这是删除事件
    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; //DOM 0级删除事件赋值null给事件处理程序名即可。
        }
    }
};

EventUtil.addHandler(input1, "click", event); //添加事件

EventUtil.removeHandler(input1, "click", event); //删除事件


注意:addHandler()与removeHandler()没有考虑到IE作用域问题。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值