(1)行内绑定
语法: //最常用的使用方式
<元素 事件=”事件处理程序”>
(2)动态绑定
//结构+样式+行为分离的页面(html+css+js事件)
语法:
对象.事件=事件处理程序
行内绑定和动态绑定的重要区别:
以上程序是不可用的,点击div时,执行test函数,这时,test中的this表示window对象
因为:
我们定义test函数,实际上相应于在window对象下定义了test属性
test(); —> 相当于 window.test();
所以test函数在执行时,里面的this指向window“谁”调用了函数,this指向“谁”
<html>
<head>
<script> window.onload=function(){ document.getElementById('btnok').onclick=function(){ alert('hello'); }; //2、动态绑定 document.getElementById('div1').onclick=test; }; </script>
</head>
<body>
<input type='button' id='btnok' value='确定'>
<script> function test(){ this.style.color='red'; } </script>
<div id='div1'>javascript</div>
</body>
</html>
以上程序是可用的,对象.onclick 在执行test函数时,test函数指向div1元素
我们能不能为一个dom对象的同一个事件指定多个事件处理程序?
例1:通过这题,我们发现,如果为一个对象的同一个事件指定多个事件处理程序,那么,后面指定的程序会覆盖前面的。
<body>
<script> function fn1(){ alert('first'); } function fn2(){ alert('second'); } window.onload=function(){ document.getElementById('div1').onclick=fn1; document.getElementById('div1').onclick=fn2; }; </script>
<div id='div1'>test</div>
</body>
如果我们想为一个对象的某个事件指定多个事件处理,可以考虑使用事件监听。
事件监听语法:
IE:
attachEvent(type,callback)
type:事件名 如:onclick、onsubmit、onchange等
callback:事件处理程序
基于W3C模型:
addEventListener(type,callback,capture)
Type:事件名 ,没有“on”前缀 如:click、submit、change
Callback:事件处理程序
Capture:事件模型 (可选参数) (冒泡模型、捕捉模型) true:捕捉模型
false:冒泡模型 (默认值)
代码示例:
<body>
<script> function fn1(){ alert('first'); } function fn2(){ alert('second'); } window.onload=function(){ document.getElementById('div1').attachEvent('onclick',fn1); document.getElementById('div1').attachEvent('onclick',fn2); }; </script>
<div id='div1'>test</div>
</body>
W3c:
<body>
<script> function fn1(){ alert('first'); } function fn2(){ alert('second'); } window.onload=function(){ document.getElementById('div1').addEventListener('click',fn1); document.getElementById('div1').addEventListener('click',fn2); }; </script>
<div id='div1'>test</div>
</body>
总结:
IE和W3C事件监听的不同:
监听方法不同:IE attachEvent 、W3C addEventListener
监听参数不同:IE 没有模型参数、W3C有模型参数 ,默认flase,为事件冒泡。
触发顺序:IE 8及以下的浏览器触发时是先绑定、后触发 W3C浏览器是先绑定、先触发
事件名称不同:IE事件需要”on”前缀,W3C不需要’on’前缀
解决事件监听的兼容性问题:
事件模型(事件的触发顺序)分为两种:Body嵌套div1,div1嵌套div2,div2嵌套div3
1)冒泡模型
2)捕捉模型
目前,IE只支持冒泡模型
事件冒泡是指事件响应时会上水冒一样上升至最顶级元素。
简单点说。冒泡就是从下往上,像鱼吐泡,泡泡是从下往上升的,也就是DOM元素被触法事件时(此时的dom元素为目标元素),目标元素事件执行后,它的祖先元素所绑定的事件会向上顺序执行。
如下代码,有四个div嵌套元素,均绑定了click事件,addEventListener函数的第三个参数设置为false说明不为捕获事件,即为冒泡事件。该代码执行结果如下:
<div id="one" style="height: 100px;background: black;">
<div id="two" style="height: 50px;background: blue;">
<div id="three" style="height: 30px;background: green;">
<div id="four" style="height: 10px;background: red;">
</div>
</div>
</div>
</div>
<script type='text/javascript'> var one=document.getElementById('one'); var two=document.getElementById('two'); var three=document.getElementById('three'); var four=document.getElementById('four'); one.addEventListener('click',function(){ alert('one'); },false); two.addEventListener('click',function(){ alert('two'); },false); three.addEventListener('click',function(){ alert('three'); },false); four.addEventListener('click',function(){ alert('four'); },false); </script>
点击one元素,输出one;
点击two元素,输出two one;
点击three元素,输出 three two one;
点击four元素,输出 four three two one;
而冒泡则相反。当触发目标元素时,会从目标元素的最顶层的祖先元素事件往下执行到目标元素为止。
将上面的代码第三个参数均改为true,则执行结果如下:
点击one,输出one;
点击two,输出one two;
点击three,输出one two three;
点击four,输出one two three four;
很明显执行顺序是不同的。
以上便是冒泡和捕获的基本理解。
首先要了解事件处理的三个阶段:事件捕获—-》目标阶段—-》事件冒泡阶段
也就是说,任何发生在 w3c事件模型 中的事件,无论是冒泡事件还是捕获事件,元素都会先进入捕获阶段,直到达到目标元素,再进入冒泡阶段。
仍然以上面的代码为例子,假设目标元素为four,也就是four被点击,执行结果是一样,那么它的执行过程呢?
如下代码:
one.addEventListener('click',function(){
alert('one');
},true);
two.addEventListener('click',function(){
alert('two');
},false);
three.addEventListener('click',function(){
alert('three');
},true);
four.addEventListener('click',function(){
alert('four');
},false);
其实过程就是,从four元素的最顶层的祖先开始向下判断是否有捕获事件的元素,从上往下,如有捕获事件,则执行;一直向下到目标元素后,从目标元素开始向上执行冒泡元素,即第三个参数为false的绑定事件的元素。(在向上执行过程中,已经执行过的捕获事件不再执行,只执行冒泡事件。)
此时点击four元素,four元素为目标元素,one为根元素祖先,从one开始向下判断执行。
one为捕获事件,输出one;
two为冒泡事件,忽略;
three为捕获时间,输出three;
four为目标元素,开始向上冒泡执行,输出four;(从此处分为两部分理解较容易。)
three为捕获已执行,忽略;
two为冒泡事件,输出two;
one为捕获已执行,忽略。
最终执行结果为:one three four two 。简单理解就是先从上到下输出ture的,然后在反过来输出flase的。
(在这里可能会有疑问,目标元素是什么事件有区别吗?我的测试结果是没有区别的,无论目标元素是捕获还是冒泡,在w3c下都是先从根元素执行捕获到目标元素,再从目标元素向上执行。)
有疑问的话可以在这个例子上将其他三个元素作为目标元素测试。
例如,three作为目标元素,执行结果为:one three two(因为two是冒泡事件,在向下执行时没有执行到。)
最后就是讨论一个DOM元素绑定多个事件的执行过程。
执行次数:绑定了几个事件便执行几次。
如下代码,two元素绑定了两个不同事件,点击two都会执行这两个事件。而执行顺序有所差异
1、如果two为目标元素,目标元素的事情按顺序执行,而其他元素根据W3C的标准执行,即先捕获后冒泡。
【是目标元素】点击two执行结果:one(因为是two的父元素支持捕获事件所以先执行) two,bubble two,capture(顺序执行,注意逗号不是间隔,是输出内容。)
2、如果目标元素不是two,则two的两个事件按先捕获后冒泡触发执行,也就是跟前面讨论的执行过程是一样的,只不过两个事件都绑定在同一个DOM元素上。
【不是目标元素】点击three执行结果:one—— two,capture—– three,bubble———-two,bubble
one.addEventListener('click',function(){
alert('one');
},true);
two.addEventListener('click',function(){
alert('two,bubble');
},false);
two.addEventListener('click',function(){
alert('two,capture');
},true);
three.addEventListener('click',function(){
alert('three,bubble');
},true);
four.addEventListener('click',function(){
alert('four');
},true);
大多数情况下,程序需要对事件冒泡进行取消?
取消事件冒泡
IE:
window.event.cancelBubble=true;
W3C:
function(event){
event.stopPropagation();
}
解决兼容性问题: public.js
1)什么是事件对象
事件对象就是事件发生时系统自动产生的对象,这个对象包含了这个事件发生时所有的信息
如:鼠标移动,那么,鼠标所在的横、纵坐标就保存到了这个事件对象中
2)如何获得事件对象
IE9及以上版本、W3C:
IE8及以下:
默认行为
有些时候,我们需要对默认行为进行取消,如表单按钮点击时,用户资料添写不完整,我们这时需要将按钮的默认行为取消。
代码示例:
解决兼容性:
Web 浏览器中可能发生的事件有很多类型,常用的事件流
对“事件处理程序过多”问题的解决方案就是事件委托。事件委托利用了事件冒泡,只指定一个事
件处理程序,就可以管理某一类型的所有事件。例如,click 事件会一直冒泡到document 层次。也就
是说,我们可以为整个页面指定一个onclick 事件处理程序,而不必给每个可单击的元素分别添加事
件处理程序。以下面的HTML 代码为例。
<ul id="myLinks">
<li id="goSomewhere">Go somewhere</li>
<li id="doSomething">Do something</li>
<li id="sayHi">Say hi</li>
</ul>
其中包含3 个被单击后会执行操作的列表项。按照传统的做法,需要像下面这样为它们添加3 个事
件处理程序。
var item1 = document.getElementById("goSomewhere");
var item2 = document.getElementById("doSomething");
var item3 = document.getElementById("sayHi");
EventUtil.addHandler(item1, "click", function(event){
location.href = "http://www.wrox.com";
});
EventUtil.addHandler(item2, "click", function(event){
document.title = "I changed the document's title";
});
EventUtil.addHandler(item3, "click", function(event){
alert("hi");
});
如果在一个复杂的Web 应用程序中,对所有可单击的元素都采用这种方式,那么结果就会有数不清的代码用于添加事件处理程序。此时,可以利用事件委托技术解决这个问题。使用事件委托,只需在DOM 树中尽量最高的层次上添加一个事件处理程序,如下面的例子所示。
var list = document.getElementById("myLinks");
EventUtil.addHandler(list, "click", function(event){
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
switch(target.id){
case "doSomething":
document.title = "I changed the document's title";
break;
case "goSomewhere":
location.href = "http://www.wrox.com";
break;
case "sayHi":
alert("hi");
break;
}
});
如果可行的话,也可以考虑为document 对象添加一个事件处理程序,用以处理页面上发生的某种特定类型的事件。
优:(1)可以节省大量内存的占用,减少事件注册,table—代理td
(2)新增子元素时,无需进行事件保定,动态部分很适合。
缺:不能什么都代理,很可能事件误判,劲酒虽好,不要贪杯哦