事件

JavaScript与HTML之间的交互是通过事件实现的。

事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间。可以使用侦听器(或是处理程序)来预定事件,以便事件发生时执行相应的代码

IE9、Firefox、Opear、Safari和Chrome全部都已经实现“DOM2级事件”模块的核心部分。

 

一、事件流

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

事件发生时元素节点之间按照特定的顺序传播,这个过程即DOM事件流

事件流:点击了某个按钮也触发了这个按钮所在的区域,同时也触发了区域所在的页面。

DOM事件流分为三个阶段1、捕获阶段;2、当前目标阶段;3、冒泡阶段

例如:为div注册了一个点击事件:

  • 事件冒泡:IE最早提出,时间开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点的过程;
  • 事件捕获:网景Netscape Communicator 最早提出,由DOM的最顶层节点开始,然后逐级向下传播到最具体的元素的接收过程。

注意:1、JS代码中只能执行捕获或是冒泡阶段的其中一个阶段

2、onclickattachEvent 只能得到冒泡阶段;

3、addEventListener(type,listener[,useCapture ])第三个参数如果是true,表示在事件捕获阶段调用事件处理程序;如果是false(不写默认就是false),表示在事件冒泡阶段调用事件处理程序。

4、在实际开发中很少使用事件捕获,更加关注事件冒泡;

5、有些事件是没有冒泡的,比如:onblur、onfocus、onmouseenter、onmouseleave

6、事件冒泡有的时候会带来麻烦,有的时候又帮助会很巧妙的做某些事件。

 

(一)、事件冒泡

IE的事件流叫做事件冒泡(event bubbling)

冒泡的是事件,而不是事件的结果,每一层对同一个事件因为执行程序不同而有不同的反应。

事件冒泡:即事件最开始由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到最不具体的节点(文档)。

举个例子:我们向水里扔了一块石头,石头会有一个下降的过程,这个过程就可以理解为从顶层向事件发生的最具体的元素(目标点)的捕获的过程

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <div>
        <button>click</button>
    </div>
</body>
</html>

点击了click按钮,浏览器会认为点击了按钮的同时也点击了包含按钮的div,点了div后又认为点击了整个HTML,点了HTML又会认为点了整个document。

这个click事件传播的顺序:1、button;2、div;3、body;4、html;5、document

也就是说,click事件首先在<button>元素上发生,这个元素就是我们要单击的元素。然后,click事件沿着DOM树向上传播,在每一个节点上都会发生,直至传播到document对象。将这个过程叫做事件冒泡。

 

(二)、事件捕获

事件捕获:不太具体的节点,应该更早接收到事件,而最具体的节点最后接收到事件。(与事件冒泡截然相反)

事件捕获的用意在于在事件到达预定目标之前捕获它。

再举个例子:我们朝着水里面扔了一块石头,石头沉了下去,但是会产生泡泡,泡泡会在沉到水底的石头最低点(最具体的元素)之后漂浮到水面上,这个过程就相当于事件冒泡。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <div>
        <button>click</button>
    </div>
</body>
</html>

先是document,然后是HTML,再到body,然后是div容器,最后是click按钮(逐级向下)

单击<button>元素就会按照顺序触发click事件:1、document;2、html;3、body;4、div;5、button

 

二、事件对象

var div = document.getElementById('box');
div.onclick = function(event){ };

1、event在这里面就是事件对象,写到侦听函数的小括号() 里面,可以当做形参来看。

2、事件对象只有有了事件才会存在,事件对象是系统自动给我们创建的,不需要我们传递参数(事件对象必定和事件相关,如果没有事件它就不存在,有了事件就存在了)

3、事件对象是 跟事件相关的一系列相关数据的集合  ,比如说 鼠标点击里面就包含了鼠标相关的信息,如鼠标坐标;如果是键盘事件里面就包含了键盘事件的信息,比如判断用户按下了哪个键。

4、事件对象可以自己命名,比如 event、ee、aa

<body>
<div class="father">
    <div class="son"></div>
</div>
<script>
    var son = document.querySelector(".son");
son.addEventListener('click',function(event){
    console.log(event);
})
</script>

为事件指定一个事件对象 event (事件对象中包含着与事件有关的信息),当我们使用console.log()打印出这个事件对象,展现的就是该事件所有相关信息。

事件目标是div,类名为son,事件类型为 click。

 

 事件对象的兼容性方案:

事件对象本身的获取存在兼容性问题:(指定事件处理函数:addEventListenter()在IE8中不兼容)

1、标准浏览器中是浏览器给方法传递的参数,只需要形参e就可以获取到;

2、IE6、IE7、IE8中,浏览器不会给方法传递参数,如果需要的话,需要通过window.event中查找获取

解决:aa = aa || window.event;

直接打印事件对象的名称就会返回undefined

使用window.event来兼容IE的低版本的浏览器

var son = document.querySelector('.son');
son.onclick = function(aa){
    //console.log(aa);
    console.log(window.event);
    //aa = aa || window.event;
    //console.log(aa);
    };

其他浏览器也可以正常解析 window.event 。有一种兼容性写法,在实际开发中并不需要过多的担心这个问题,直接按照正常情况来写就没有问题。

aa = aa || window.event;
console.log(aa);

 

三、常见事件对象的属性和方法

(一)事件对象属性和方法

事件对象属性方法 说明
e.target 返回触发事件的对象          标准
e.srcElement 返回触发事件的对象          非标准 IE6-8使用
e.type 返回事件的类型(比如 click、mouseover不带on)
e.cancelBubble 该属性阻止冒泡                 非标准 IE6-8使用
e.returnValue 该属性 阻止默认事件(默认行为) 非标准 IE6-8 使用,比如不让链接跳转               
e.preventDefault() 该方法 阻止默认事件(默认行为) 标准,比如不让链接跳转
e.stopPropagation()              阻止冒泡  标准

 

 注意:得先写事件对象,才能使用事件对象里面的属性。

(二)e.target 和 this 的区别

1、e.target 返回的是触发事件的对象(元素)目标;

2、this 返回的是绑定事件的对象;

区别:e.target  点击了哪个元素就返回那个元素;

this  绑定了哪个元素就返回哪个元素。那么就返回谁。

<body>
<div>12345</div>
<ul>
    <li>aaa</li>
    <li>aaa</li>
    <li>aaa</li>
</ul>
<script>
    var div = document.querySelector('div');
    div.addEventListener('click',function(e){
    console.log(e.target);
    console.log(this);
});
</script>

 实例2:


 给ul绑定了单击事件,那么this指向的就是ul

e.target  指向我们点击的那个对象(那个元素触发的对象),点击的是li,所以e.target 指向的就是 li

    var ul = document.querySelector('ul');
    ul.addEventListener('click',function(e){
    console.log(e.target);
    console.log(this);
});

 

 浏览器兼容:

了解兼容性即可,e.target 适用于标准浏览器,e.srcElement 适用于非标准浏览器 (IE6~8浏览器

跟 this 有个非常相似的属性  currentTarget ,不过这个 currentTarget 属性 IE6~8 不兼容。

<body>
<div>12345</div>
<ul>
    <li>aaa</li>
    <li>aaa</li>
    <li>aaa</li>
</ul>
<script>
    var div = document.querySelector('div');
    div.onclick = function(e){
    e = e || window.event;
    var target = e.target || e.srcElement;
    console.log(target);
}
</script>

 

 (三)阻止默认行为

属性:

1、e.type 返回事件类型

2、e.returnValue() 该属性 阻止默认事件(默认行为)非标准 IE6~8使用(例如 不让链接跳转)

3、e.preventDefault() 该方法 最值默认事件(默认行为)标准(例如 不让链接跳转)

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
<style>

</style>
</head>
<body>
<div>123</div>
   <a href="http://www.baidu.com">baidu</a>
   <form action="http://www.baidu.com">
    <input type="submit" value="submit" name="sub">
   </form>
<script>
//常见事件对象的属性和方法
//1、返回事件类型
    var div = document.querySelector('div');
    div.addEventListener('mouseover',hs);
    div.addEventListener('click',hs);
    function hs(e){
    console.log(e.type);
    }
//阻止默认行为(事件)让链接不跳转,或是让提交按钮不提交
//DOM标准写法
var a = document.querySelector('a');
a.addEventListener('click',function(e){
     //e.preventDefault();
});
//传统的注册方式
a.onclick = function(e){
//普通浏览器 e.preventDefault();方法
    e.preventDefault();
//IE浏览器  IE6、7、8 e.returnValue;属性
    e.returnValue;
//也可以使用 return false 也可阻止默认行为,没有兼容性问题,return后面的代码不会被执行,而且只限于传统的注册方式。
    return false;
 alert(11111); }
</script> </body> </html>

 1、事件处理程序

2、传统注册方式

e.preventDefault();    普通浏览器 e.preventDefault();方法

e.returnValue;   IE浏览器 IE678 e.returnValue;属性

return false;    也可以使用 return false 也可阻止默认行为,没有兼容性问题

 

 

四、事件处理程序

事件就是用户或浏览器自身执行的某种动作,例如 click、load和mouseover,这些都是事件的名字。

而响应某个事件的函数就叫做事件处理程序(或 事件侦听器)。

事件处理程序的名字以 "on" 开头,因此click事件处理程序就是 onclick ,load事件的事件处理程序就是onload。

为事件指定程序有三种方式:

(一)HTML事件处理程序

某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的HTML特性来指定。这个特性的值应该是应该能够执行的JavaScript代码。

实例1:


 要在按钮被单击时执行一些JS代码

<button onclick="alert('clicked')">click</button>

 表现效果:单击这个按钮时就会显示出一个警告框

 这个操作是通过制定onclick特性并将一些JS代码作为它的值来定义的。

由于这个值是JavaScript ,因此不能再其中使用未经转义的HTML语法字符,例如和号(&)、双引号(" ")、小于号(<)、大于号(>)。

为了避免使用HTML实体,这里使用了单引号,如果想使用双引号,可以使用(&quot;  双引号的转义字符)

<button onclick="alert(&quot; clicked &quot;)">click</button>

 

实例2


 在HTML中定义的事件处理程序可以包含要执行的具体动作,也可以调用在页面其他地方定义的脚本,如下例所示:

<button onclick="aa()">click</button>
<script>
    function aa(){
        alert("hello world!")
    }
</script>

 在这个例子中,单击按钮就会调用 aa() 函数。

这个函数是放在一个独立的 <script> 元素中定义的,当然也可以被包含在一个外部文件中。事件处理程序中的代码在执行时,有权访问全局作用域中的任何代码。

 

实例3


 这样指定事件处理程序具有一些独到之处。这样会创建一个封装着元素属性值的函数,这个函数中有一个局部变量event,也就是事件对象。

<button onclick="alert(event.type)">click</button>

 通过event变量,可以直接访问事件对象。无需自己定义,也不用从函数的参数列表中读取。

 

实例4


 在这个函数内部,this值等于事件的目标函数

<span onmouseover="this.style.color='red'" >test</span>

this代表事件作用的这个标签本身(上例中this代表span标签本身)

 

(二)HTML0 级事件处理程序

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

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

实例1:


 

 var bq = document.getElementById("bq");
    bq.onclick = function(){
        alert("click");
    }

在这里,通过文档对象获得了一个按钮的id,然后为它指定了onclick事件处理程序。

注意:在这些代码运行以前不会指定事件处理程序,因此如果这些代码在页面中位于按钮后面,就有可能在一段时间内怎么单击都没有反应。

 

使用DOM0 级方法指定的事件处理程序被认为是元素的方法。因此,这时候的事件处理器是在元素的作用域中运行的程序中的this元素引用当前的元素;

实例2:


<input type="button" value="click" id="bq">
<script>
 var bq = document.getElementById("bq");
    bq.onclick = function(){
        alert(this.id);
    }
</script>

 点击按钮显示的是元素的ID,这个ID是通过this.id取得的。不仅仅是ID,实际上可以在事件处理程序中通过 this 访问该元素的任何属性和方法。以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理。

 

删除事件处理程序

删除通过DOM0 级方法指定的事件处理程序,只需要将事件处理程序属性的值设置为null即可。将事件处理程序设置为null之后,再单击按钮将不会有任何动作发生。

bq.onclick = null;   //删除事件处理函数

 注意:如果使用HTML指定事件处理程序,那么onclick属性的值就是一个包含着在同名HTML特性中指定代码的函数。而将相应的属性设置为null,也可以删除以这种方式指定的的时间处理函数。

 

(三)DOM2 级事件处理程序

DOM2 级事件定义了两个方法:指定事件处理函数:addEventListenter(); 和删除事件处理程序的操作:removeEventListener();

所有的DOM节点都包含这两个方法,并且都接受3个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。

布尔值为true,表示在捕获阶段调用事件处理程序;

布尔值为false(不写默认就是false),表示在冒泡阶段调用事件处理程序;

 

(一)指定事件处理函数:addEventListenter()

实例1:


 在按钮上为click事件添加事件处理程序

<input type="button" value="click" id="bq">
<script>
 var bq = document.getElementById("bq");
    bq.addEventListener("click",function(){
        alert(this.id);},false);
</script>

上面这个例子中为按钮添加了 onclick 事件处理程序,并且这个事件处理程序会在冒泡阶段被触发(因为最后一个参数是false)。

和DOM0 级方法一样,这里添加的事件处理函数也是在其依附的元素的作用域中运行。

使用DOM2 级方法添加事件处理程序的主要好处是可以添加多个事件处理函数

 

实例2:


 为bq添加多个事件处理函数

<input type="button" value="click" id="bq">
<script>
 var bq = document.getElementById("bq");
    bq.addEventListener("click",function(){
        alert(this.id);},
false);
    bq.addEventListener("click",function(){
        alert("hello world !");},
false);
</script>

 在这里为按钮添加了两个事件处理函数,两个事件处理函数会按照添加的先后顺序依次触发,因此在这里会先显示元素的ID,然后再显示" hello world !" 的提示信息。

 

实例3:


 捕获阶段:如果addEventListener 的三个参数是 true ,那么就处于捕获阶段 document —> html —> body —> father —> son

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
<style>
    .father{width:100px;height:100px;background:#faa;margin:100px auto;}
    .son{width:50px;height:50px;background:#aaf;margin:auto}
</style>
</head>
<body>
<div class="father">
    <div class="son"></div>
</div>
<script>
    var son = document.querySelector(".son");
son.addEventListener('click',function(){
    alert('son');
    },true)
    var father = document.querySelector(".father");
father.addEventListener('click',function(){
    alert('father');
    },true)
</script>
</body>
</html>

 点击子元素盒子,会先弹出 father警示框,再点击确认之后才会出现 son警示框。从上到下捕获。

 

 实例4:


 冒泡阶段:如果addEventListener 的三个参数是 false,那么则处于冒泡阶段,son —> father —> body —> html—> document

<script>
    var son = document.querySelector(".son");
son.addEventListener('click',function(){
    alert('son');
    },false)
    var father = document.querySelector(".father");
father.addEventListener('click',function(){
    alert('father');
    },false)
</script>

 现在处于冒泡阶段,先从son开始,点击son的时候son警示框先弹出,点击确定之后,继续向上冒泡,father里面也有一个侦听器,所以father警示框弹出。

 

(二)移除事件处理程序

通过  addEventListener(); 添加的事件处理程序只能使用  removeEventListener()  来移除;移除时传入的参数和添加程序处理程序时使用的参数相同。

这也意味通过 addEventListener() 添加的匿名函数(没有传入参数)将无法移除

实例3


 var bq = document.getElementById("bq");
    bq.addEventListener("click",function(){
        alert(this.id);},
false);
    bq.removeEventListener("click",function(){//无用
        alert(this.id);},
false);

在这个例子中,我们使用 addEventListener() 添加了一个事件处理函数,虽然调用了 removeEventListener() 时看似使用了相同的参数,但是实际上,第二个参数与传入的addEventListener() 中的参数是完全不同的参数。

 

实例4


 传入removeEventListener() 中的事件处理程序参数 必须与传入addEventListener()中的相同

 var bq = document.getElementById("bq");
var handle = function(){
    alert(this.id);
};
bq.addEventListener("click",handle,false);
bq.removeEventListener("click",handle,false);

将事件处理器写成这个样子没有问题,这只因为在addEventListener() removeEventListener() 中使用了相同的函数。

大多数情况,都是将事件处理程序添加到事件流的冒泡阶段,这样就可以最大限度上的兼容各种浏览器。最好只在需要在事件到达目标之前截获它的时候将事件处理程序添加到捕获阶段。

如果不是特别需要,不建议在事件捕获阶段注册事件处理程序。

IE9、FireFox、Safari、Chrome和Opera支持DOM2 级事件处理程序。

 

posted on 2019-11-03 20:58  Cloud%  阅读(642)  评论(0编辑  收藏  举报