事件处理函数
事件处理函数
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
type的一种用法。把所有事件设置成一个函数,然后用switch循环 通过e.type的不同。设置不同内容

Event对象获取方式
e.clientX,e.clinetY(返回当事件被触发时,当前body可视距离的鼠标指针的水平和垂直坐标)
e.pageX,e.pageY(当前鼠标距离整体页面的水平和垂直坐标)
e.offsetX,e.offsetY(鼠标距离事件源的左边和上边距离)
pageX pageY有兼容问题 ie9以后才支持
兼容写法


一.事件流
事件冒泡和事件捕获分别由微软和网景公司提出,这两个概念是为了解决页面中事件流(事件发生顺序)的问题。
上面的代码当中一个div元素当中有一个p子元素,如果两个元素都有一个click的处理函数,那么我们怎么才能知道哪一个函数会首先被触发呢?
为了解决这个问题微软和网景提出了两种几乎完全相反的概念。
1.事件冒泡
微软提出了名为事件冒泡的事件流。事件冒泡可以形象地比喻为把一颗石头投入水中,泡泡会一直从水底冒出水面。也就是说,事件会从最内层的元素开始发生,一直向上传播,直到document对象。
因此上面的例子在事件冒泡的概念下发生click事件的顺序应该是p -> div -> body -> html -> document
2.事件捕获
网景提出另一种事件流名为事件捕获与事件冒泡相反,事件会从最外层开始发生,直到最具体的元素。
上面的例子在事件捕获的概念下发生click事件的顺序应该是document -> html -> body -> div -> p
3.W3C事件阶段(event phase):
当一个DOM事件被触发的时候,他并不是只在它的起源对象上触发一次,而是会经历三个不同的阶段。简而言之:事件一开始从文档的根节点流向目标对象(捕获阶段),然后在目标对向上被触发(目标阶段),之后再回溯到文档的根节点(冒泡阶段)如图所示(图片来自W3C):
事件的三个阶段
事件捕获阶段(Capture Phase)
事件从文档的根节点出发,随着DOM树的结构向事件的目标节点流去。途中经过各个层次的DOM节点,并在各节点上触发捕获事件,直到到达时间的目标节点。捕获阶段的主要任务是简历传播路径,在冒泡阶段,时间会通过这个路径回溯到文档根节点。
例如,通过下面的这个函数来给节点设置监听,可以通过将;设置成true来为事件的捕获阶段添加监听回调函数。
而,在实际应用中,我们并没有太多使用捕获阶段监听的用例,但是通过在捕获阶段对事件的处理,我们可以阻止类似click事件在某个特定元素上被触发。如下:
如果你对这种用法不是很了解的话,建议设置为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事件里面去写代码了,是不是很方便呢。





浙公网安备 33010602011771号