事件处理函数

事件处理函数

onmouseover 鼠标指针悬停在某个元素上出发的一个动作

onmouseout  鼠标离开某个元素触发的一个动作

onclick  点击动作

添加事件的语法 event = "javascript statment(s)"   js代码包含在一对引号之间 可以把任意数量的js语句放入引号中,用分号隔开

点击链接时,js语句会被调用,同时链接的默认行为也会被调用

比如<a href="http://www.baidu.com" onclick="alert(1)">123</a>  会调用alert(1),然后会转到www.baidu.com

如果要阻止调用默认行为 就在js语句中 加上return false ,让js代码返回的值为false 事件处理函数就会认为这个函数没有被调用

比如 <a href="http://www.baidu.com" onclick="alert(1);return false">123</a>

 

如果想把一个事件添加到某个特定ID属性的元素上,给getElementById(id).event=action

例子

事件对象

当触发某个事件时,会产生一个事件对象,这个对象包含着所以与事件有关的信息,包括导致事件的元素,事件的类型,以及其他与特点事件相关的信息

通过与事件绑定的执行函数是可以得到一个隐藏参数的。说明,浏览器会自动分配一个参数,这个参数其实就是event对象

    老版本IE支持window.event  兼容写法 e=e||window.event

bubbles 返回布尔值,指示事件是否是起泡事件类型。
cancelable
返回布尔值,指示事件是否可拥可取消的默认动作。
currentTarget
返回其事件监听器触发该事件的元素。跟this一样
eventPhase
返回事件传播的当前阶段。
target 返回触发此事件的元素(事件的目标节点)。   老版本的IE中不支持target,而是支持e.srcElement 兼容写法 e.target=e.targe||e.srcElement
timeStamp
返回事件生成的日期和时间。
type 返回当前 Event 对象表示的事件的名称。

type的一种用法。把所有事件设置成一个函数,然后用switch循环 通过e.type的不同。设置不同内容

 

 

Event对象获取方式

e.clientX,e.clinetY(返回当事件被触发时,当前body可视距离的鼠标指针的水平和垂直坐标)

e.pageX,e.pageY(当前鼠标距离页面的水平和垂直坐标)

e.offsetX,e.offsetY(鼠标距离事件源的左边和上边距离)

pageX pageY有兼容问题 ie9以后才支持

兼容写法 

 

 

 

 

offsetLeft: 获取自身左外边框到定位父级的左内边框的距离
offsetTop 获取自身上外边框到定位父级的上内边框的距离 只能获取不能修改 
keydown 鼠标按下的时候  用的时候是要加on的
keyup  鼠标弹起的时候    用的时候是要加on的
差别是keydown的时候 我们按下的键还没到文本框,还有机会取消;而kewup鼠标弹起的时候按下的键已经到了文本框
e.keyCode 键盘码 0-9是键盘码48-57  小键盘的数字是96-105   8是删除键  
e.preventDefault() 取消默认行为

 

一.事件流

事件冒泡和事件捕获分别由微软和网景公司提出,这两个概念是为了解决页面中事件流(事件发生顺序)的问题。

<div id="outer">
    <p id="inner">Click me!</p>
</div>

上面的代码当中一个div元素当中有一个p子元素,如果两个元素都有一个click的处理函数,那么我们怎么才能知道哪一个函数会首先被触发呢?

为了解决这个问题微软和网景提出了两种几乎完全相反的概念。

1.事件冒泡

微软提出了名为事件冒泡的事件流。事件冒泡可以形象地比喻为把一颗石头投入水中,泡泡会一直从水底冒出水面。也就是说,事件会从最内层的元素开始发生,一直向上传播,直到document对象。

因此上面的例子在事件冒泡的概念下发生click事件的顺序应该是p -> div -> body -> html -> document

2.事件捕获

网景提出另一种事件流名为事件捕获与事件冒泡相反,事件会从最外层开始发生,直到最具体的元素

上面的例子在事件捕获的概念下发生click事件的顺序应该是document -> html -> body -> div -> p

3.W3C事件阶段(event phase):

当一个DOM事件被触发的时候,他并不是只在它的起源对象上触发一次,而是会经历三个不同的阶段。简而言之:事件一开始从文档的根节点流向目标对象(捕获阶段),然后在目标对向上被触发(目标阶段),之后再回溯到文档的根节点(冒泡阶段)如图所示(图片来自W3C):

image

事件的三个阶段

事件捕获阶段(Capture Phase)

事件从文档的根节点出发,随着DOM树的结构向事件的目标节点流去。途中经过各个层次的DOM节点,并在各节点上触发捕获事件,直到到达时间的目标节点。捕获阶段的主要任务是简历传播路径,在冒泡阶段,时间会通过这个路径回溯到文档根节点。

例如,通过下面的这个函数来给节点设置监听,可以通过将;设置成true来为事件的捕获阶段添加监听回调函数。

element.removeEventListener(&ltevent-name>, <callback>, <use-capture>);

而,在实际应用中,我们并没有太多使用捕获阶段监听的用例,但是通过在捕获阶段对事件的处理,我们可以阻止类似click事件在某个特定元素上被触发。如下:

var form=document.querySeletor('form');
form.addEventListener('click',function(e){
  e.stopPropagation();
  },true);

 

如果你对这种用法不是很了解的话,建议设置为false或者undefined,从而在冒泡阶段对事件进行监听,这也是常用的方法。

目标阶段(Target Phase)

当事件到达目标节点时,事件就进入了目标阶段。事件在目标节点上被触发,然后逆向回流,知道传播到最外层的文档节点。

对于多层嵌套的节点,鼠标和指针事件经常会被定位到最里层的元素上。假设,你在一个div元素上设置了click的监听函数,而用户点击在了这个div元素内部的p元素上,那么p元素就是这个时间的目标元素。事件冒泡让我们可以在这个div或者更上层的元素上监听click事件,并且时间传播过程中触发回调函数。

冒泡阶段(Bubble Phase)

事件在目标事件上触发后,并不在这个元素上终止。它会随着DOM树一层层向上冒泡,直到到达最外层的根节点,一直向上传播,直到document对象。也就是说,同一事件会一次在目标节点的父节点,父节点的父节点...直到最外层的节点上触发。

绝大多数事件是会冒泡的,但并非所有的。

阻止冒泡

方式有两种

1、e.cancelBubble =true;

2、e.stopPropagation();

事实上stoppropagation和cancelBubble的作用是一样的,都是用来阻止浏览器默认的事件冒泡行为。

不同之处在于stoppropagation属于W3C标准,试用于Firefox等浏览器,但是不支持IE浏览器。相反cancelBubble不符合W3C标准,而且只支持IE浏览器。所以很多时候,我们都要结合起来用。不过,cancelBubble在新版本chrome,opera浏览器中已经支持。

例子

事件委托

利用事件冒泡的原理,把本应该添加在某元素上的事件委托给他的父级(外层)

阻止默认浏览器默认行为

return false

var evt=e || event

evt.preventDefault();

evr.returnValue=false

 

DOM2级事件处理程序

添加事件监听器:addEventListener(事件名,处理函数,布尔值)//事件名不带on

处理函数可以写具体的函数体,也可以写函数指针    可选布尔值,指定事件是否在捕获或冒泡阶段执行。默认是false代表冒泡,true是捕获 可以多次添加事件,而不是像onclick只能添加

var demo =document.getElementById("demo");
demo.addEventListener('click' , function(){alert(123)}
)//事件名不用带on
demo.addEventListener('click' , function(){alert(456)}
)
添加了两个事件

 

 

移除事件监听器 :removeEventListener(事件名,处理函数)//事件名带on

 

var demo =document.getElementById("demo");
demo.addEventListener('click' , function(){alert(123)}
)//事件名不用带on
demo.addEventListener('click' , function(){alert(456)}
)
//添加了两个事件
但是想要移除事件 就不能使用匿名函数,因为匿名函数只能访问一次
所以得给函数命名。再添加事件
function abc(){
alert(123);
}
demo.addEventListener("click",abc)
现在移除事件才能访问到函数
demo.removeEventListener("click",abc);
//从demo移除了点击函数abc

 

IE下事件监听器:attachEvent(事件名,处理函数)//事件带on   只有两个参数  只有事件冒泡

 

var demo =document.getElementById("demo");
demo.attachEvent('onclick' , function(){alert(123)}
)//事件名用带on
demo.addEventListener('onclick' , function(){alert(456)}
)
添加了两个事件 ie9以前才支持

 

 

 

 

IE下移除事件监听器 detachEvent(事件名,处理函数)  ie9-10才支持

 

var demo =document.getElementById("demo");
demo.addEventListener('click' , function(){alert(123)}
)//事件名不用带on
demo.addEventListener('click' , function(){alert(456)}
)
//添加了两个事件
但是想要移除事件 就不能使用匿名函数,因为匿名函数只能访问一次
所以得给函数命名。再添加事件
function abc(){
alert(123);
}
demo.addEventListener("click",abc)
现在移除事件才能访问到函数
demo.detachEvent("onclick",abc);//带ON
//从demo移除了点击函数abc

    

监听器和事件不同的是,可以给一个事件添加多个处理函数,只需要添加多个监听器就行,但是事件只能添加一个,会被后面的覆盖,比如一个onclick事件。多个监听器可以让点击一次 触发多个函数,onclick则只会触发最后一个

兼容性IE写法

 

 

event对象中 target和currentTarget 属性的区别。

 

首先本质区别是:

  • event.target返回触发事件的元素

  • event.currentTarget返回绑定事件的元素

  

复制代码
复制代码
 1     <ul id="ul">ul
 2         <li>li<a href="">a</a></li>
 3         <li>li<a href="">a</a></li>
 4         <li>li<a href="">a</a></li>
 5     </ul>
 6     <script>
 7         var ul = document.getElementById("ul");
 8         ul.onclick = function(event){
 9             var tar = event.target;
10             var tagName = tar.nodeName.toLowerCase();
11             console.log("你点击了:"+tagName);
12             event.preventDefault();
13         }
14     </script>
复制代码
复制代码

  当我点击哪个元素时,event.target返回的是点击的元素节点,我们可以用返回的节点使用一些DOM对象上的一些操作。这里event.preventDefault,是用来阻止点击a默认跳转,刷新页面导致结果不能输出来的一个作用。

event.currentTarget的作用是什么呢,我觉得他和this 的作用是差不多的,始终返回的是绑定事件的元素

  

复制代码
复制代码
 1 <ul id="ul">ul
 2         <li>li<a href="">a</a></li>
 3         <li>li<a href="">a</a></li>
 4         <li>li<a href="">a</a></li>
 5     </ul>
 6     <script>
 7         var ul = document.getElementById("ul");
 8         ul.onclick = function(event){
 9             var tar = event.target;
10             var current = event.currentTarget;
11             var tagName = tar.nodeName.toLowerCase();
12             console.log(tar == this);
13             event.preventDefault();
14         }
15     </script>
复制代码
复制代码

实际使用中target的妙用:

  target事件委托的定义:本来该自己干的事,但是自己不干,交给别人来干。比如上面的例子中,应该是ul li a 来监控自身的点击事件,但是li a自己不监控这个点击事件了,全部交给li父节点和a祖父节点ul来监控自己的点击事件。一般用到for循环遍历节点添加事件的时候都可以用事件委托来做,可以提高性能

来个案例:一个添加删除的demo。

复制代码
复制代码
 1   <input type="text" id="text">
 2     <input type="button" value="添加" id="button">
 3     <ul>
 4         <li>第1个<button class="btn" id="1">删除</button></li>
 5         <li>第2个<button class="btn" id="2">删除</button></li>
 6         <li>第3个<button class="btn" id="3">删除</button></li>
 7     </ul>
 8     <script>
 9             var button = document.getElementById("button");
10             var text = document.getElementById("text");
11             var ul = document.getElementsByTagName("ul")[0];
12             var btnClass = document.getElementsByClassName("btn");        
13         button.onclick = function(){
14             var deleteButton = document.createElement("button");    
15             var value = text.value;
16                 deleteButton.setAttribute("class","btn");// setAttribute是设置 input 元素属性类型
17             var deleteText = document.createTextNode("删除");//创造了一个删除button键
18                 deleteButton.appendChild(deleteText);
19             var li = document.createElement("li");
20             var liText = document.createTextNode(value);//创造了Li元素,把input的内容加了进去
21                 li.appendChild(liText);
22                 li.appendChild(deleteButton);//把删除button添加到了li里面
23                 ul.appendChild(li);
24             for(var i=0;i<btnClass.length;i++){
25                 btnClass[i].onclick=function(){
26                 this.parentNode.parentNode.removeChild(this.parentNode);
27             }
28         }
29         }
30 

36             }
37     </script>
复制代码
复制代码

为什么在第24行也需要一个for循环,给每个删除按钮添加事件呢,因为外面的for循环,在文档刷新时给页面中存在的三个删除按钮添加了点击事件,而后来添加的删除按钮并没有绑定事件,导致页面中存在的三个li标签可以删除,而后来新添加的li不能删除这个问题。我们使用事件委托来做就不用这么麻烦了

复制代码
复制代码
 1 <script>
 2             var button = document.getElementById("button");
 3             var text = document.getElementById("text");
 4             var ul = document.getElementsByTagName("ul")[0];
 5             var btnClass = document.getElementsByClassName("btn");        
 6         button.onclick = function(){
 7             var deleteButton = document.createElement("button");    
 8             var value = text.value;
 9                 deleteButton.setAttribute("class","btn");
10             var deleteText = document.createTextNode("删除");
11                 deleteButton.appendChild(deleteText);
12             var li = document.createElement("li");
13             var liText = document.createTextNode(value);
14                 li.appendChild(liText);
15                 li.appendChild(deleteButton);
16                 ul.appendChild(li);
17             }
18             ul.onclick = function(event){
19                 var tar = event.target;
20                 if(tar.nodeName.toLowerCase() == "button"){
21                     tar.parentNode.parentNode.removeChild(tar.parentNode);
22                 }
23             }
24     </script>
复制代码
复制代码

给ul添加了点击事件,点击ul里面的子元素,event.target都会返回当前点击的元素节点,做一个判断,如果点击了button标签,删除这个li节点。由于添加的li都在ul节点里面,所以并不用再去添加li事件里面去写代码了,是不是很方便呢。

 

 

 

 

 

posted @ 2020-05-28 22:41  Ren小白  阅读(568)  评论(0)    收藏  举报
levels of contents