我们通过下面一个实例,进行说明。
<body>
<h1>Event Flow</h1>
<ul id="nav">
<li><a href="../image-load/image-load.html">Image-Load</a></li>
<li><a href="../click/click.html">Click</a></li>
<li><a href="../move/move.html">Move</a></li>
<li><a href="../address/address.html">Address Form</a></li>
<li><a href="../follow/follow.html">Follow</a></li>
<li><a href="../flow/flow.html">Flow</a></li>
<li><a href="../keys/keys.html">Key Press</a></li>
<li><a href="../load/load.html">addLoadEvent</a></li>
</ul>
<div id="content">
<ul id="list1">
<li>
<p>List 1 </p>
<ul id="list2">
<li>
<p>List 2 </p>
<ul id="list3">
<li>
<p>List 3 </p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul id="list4">
<p>List 4 </p>
</ul>
</div>
</body>
提供的CSS样式通过设置第三个嵌套列表的位置,使其在视觉上处于祖先元素之外、且位于第四个列表之上
#list1 { height:80px;
} #list2 { margin-top: 10px; height:20px;
} #list3 { position:absolute; top:190px; left:150px;
} #list4 { margin-top:10px; height:100px;
}
//主要任务就是修改被单击元素的属性
addEvent(window,'load',function(){ //为了演示问题所在,使用一个修改后的addEvent方法
function modifiedAddEvent(obj,type,fn) { if (obj.addEventListener) { //W3C方式
/*这个方法在第一章的addEvent()方法基础上进行修改, 修改后启用了捕获阶段而取消了冒泡阶段*/ obj.addEventListener(type,fn,true); } else if (obj.attachEvent) { //ms 方式
obj['e'+type+fn]=fn; obj[type+fn]=function(){obj['e'+type+fn](window.event);} obj.attachEvent('on'+type,obj[type+fn]); } else { return false; } } var counter=0; //取得无序列表
var lists=document.getElementsByTagName('ul'); for (var i = 0 ;i<lists.length ;i++ ) { //注册单机事件侦听器
modifiledAddEvent(lists[i],'click',function(){ //向段落添加表示捕获单机事件先后顺序的数字
var append=document.createTextNode(':'+counter++); this.getElementsByTagName('p')[0].appendChild(append); //修改类名以突出显示被单击的元素
this.className='clicked'; }); } });
老实说,我现在又到了没有耐心的时刻了,看书看不下去。所以上文看的也是迷迷糊糊。但是想到,我一定要坚持下去,我不能浮躁。要不我今天先休息。明天继续学习。//我还是客服了我浮躁的内心,静下心来看了看前面的代码,并且理解了,这样可以继续看下去了
之所以点击list3的时候12都做出了相应的变化,是因为当你单击list3的时候,也单击了其祖先列表
阻止冒泡
function stopPropagation(eventObject) { eventObject=eventObject||getEventObject(eventObject); if (eventObject.stopPropagation) { eventObject.stopPropagation(); } else { eventObject.cancelBubble=true; } } window['ADS']['stopPropagation']=stopPropagation;
阻止事件
function preventDefault(eventObject) { eventObject=eventObject||getEventObject(eventObject); if (eventObject.preventDefault) { eventObject.preventDefault(); } else { eventObject.returnValue=false; } } window['ADS']['preventDefault']=preventDefault;
二、注册事件
<a href="www.baidu.com" onclick="window.opent(this.href);return false;">http://baidu.com/</a>
function addEvent(obj,type,fn) { if(obj.attachEvent) { obj['e'+type+fn]=fn; obj[type+fn]=function(){obj['e'+type+fn](window.event);} obj.attachEvent('on'+type+obj[type+fn]); } else obj.addEventListner(type,fn,false); }
window.onload=function() { var anchor=document.getElementById('example'); anchor.onclick=function() { //单击事件时候执行代码
} }
Microsoft特有的事件模型
function eventListener() { //响应单击事件的代码
} window.attachEvent('onload',function(){ var link = document.getElementById('example'); //增加事件
link.attachEvent('onclick',eventListener); //去除事件
//link.detachEvent('onclick',eventListener);
});
//w3c事件注册
function eventListener() { //响应单击事件的代码
} window.addEventListener('load',function(W3CEvent)) { var link = document.getElementById('example'); link.addEventListener('click',eventListener,false); },false); //移除事件监听器
link.removeEventListener('click',eventListener,false);
无论那种事件注册方法,load事件会一直等到所有图像全部加载完之后才被调用,要解决这问题,我们要在ADS库中添加如下方法
function addLoadEvent(loadEvent,waitForImage) { if (!isCompatible()) { return false; } //如果等标记是ture则使用常规的添加事件的方法
if (waitForImage) { return addEvent(window,'load',loadEvent); } //否则使用一下不同的方式包装loadEvent()方法
//一边为this关键字指定正确的内容,同事确保事件不会被执行两次
var init = function() { //如果这个函数已经被调用了,则返回
if (argument.callee.done) { return; } //标记这个函数,以便检查他是否运行过
arguments.callee.done=true; //在document的环境中运行载入事件
loadEvent.apply(document,arguments); }; //为DOMContentLoad事件注册事件侦听器
if (document.addEventListener) { document.addEventListener("DOMContenLoaded",init , false); } //对于safari使用setInterval()函数检测document是否咱如完成
if (/WebKit/i.test(navigator.userAgent)) { var _timer=setInterval(function(){ if (/loaded|complete/.test(document.readyState)) { clearInterval(_timer); init(); } },10); } //对于IE(使用条件注释),附加一个在载入过程最后执行的脚本。
//并检测该脚本是否载入完成
/*@cc_on*/
/*if(@_win32) document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>"); var script=document.getElementById("__ie_onload"); script.onreadystateChange=function() { if (this.readyState=='complete') { init(); } }; /*@end @*/
return true; } window['ADS']['addLoadEvent']=addLoadEvent;
跨浏览器的事件属性和方法
定义了下列属性。
bubbles:是否是冒泡事件;
cancelable:是否可以被取消默认动作;
currentTarget:是当前正在处理的事件侦听器所在的事件流中的DOM元素;
target:是DOM文档中最早调用事件序列的目标对象(EventTarget对象的实例);
timestamp:是一个DOMTimeStamp对象,确定子创建事件的纪元事件算起经过的毫秒数。但不一定在所有系统中都有效
type:包含时间名称的字符串值
eventPhase:当前事件侦听器出去事件流的那个阶段123~也可以用如下:
function eventListener(W3CEvent) { switch (W3CEvent.eventPhase) { case Event.CAPTURING: //如果处于捕获阶段要运行的代码
break; case Event.AT_TARGET //如果当前目标对象要运行的代码
break; case Event.BUBBLING_PHASE: //如果处于冒泡阶段要运行的代码
break; } }
W3C DOM2事件模型也定义了下列的Event对象方法
initEvent(eventType,canBubble,cancelable):用于初始化通过document.createEvent('Event')方法创建的事件对象。
preventDefalt():用于取消对象的默认动作
stopPropagation()用于停止事件流的进一步执行,包括捕获阶段、目标对象和冒泡阶段。
DOM2事件规范定义的MouseEvent对象:
MouseEvent对象属性:altKey,ctrlKey,shiftKey,分别表示在鼠标事件发僧是否按住了键盘上的Alt,Ctrl,Shift键
button ,button中会包含表示哪个鼠标键按下的一个整数值。鼠标山每个键与证书的对应关系:
0表示鼠标的左键;1表示中(如果有)2表示右
if (W3CEvent.button==0) { //左键的单机事件
} //或者
if (W3CEvent.button==MouseEvent.BUTTON_LEFT) { //左键单击的代码
}
还有clientX和clientY类似的还有screenX和screenY
document.addEventListener('click',function(W3CEvent){ alert('client:('+W3CEvent.clientX+','+W3CEvent.clientY+')'); },false);
处理诸多不兼容性问题
function getTarget(eventObject) { eventObject=eventObject||getEventObject(eventObject); //如果是W3C或者MSIE的模型
var target=eventObject.target||eventObject.srcElement; //如果想Safari中一样是一个文本节点,重新将目标对象指定为父元素
if (target.nodeType==ADS.node.TEXT_NODE) { target=node.parentNode; } return target; } window['ADS']['getTarget']=getTarget;
通过这个方法,可以取得给定事件的目标:
ADS.addEvent(window,'load',function(){ function eventListener(W3CEvent) { //取得目标
var target=ADS.getTarget(W3CEvent); //target现在引用的是一个适当的元素
window.open(target.href); } var anchor = document.getElementById('example'); addEvent(anchor,'click',eventListener); });
function getMouseButton(eventObject) { eventObject = eventObject || getEventObject(eventObject); // Initialize an object wit the appropriate properties
//使用适当的属性初始化一个对象变量
var buttons = { 'left':false, 'middle':false, 'right':false }; /*检查eventObject对象的toString()方法的值,W3C DOM对象有toString方法 并且此时可方法的返回值应该是MouseEvent*/
// Check the toString value of the eventObject
// W3C Dom object have a toString method and in this case it
// should be MouseEvent
if(eventObject.toString && eventObject.toString().indexOf('MouseEvent') != -1) { // W3C Method
switch(eventObject.button) { case 0: buttons.left = true; break; case 1: buttons.middle = true; break; case 2: buttons.right = true; break; default: break; } } else if(eventObject.button) { // MSIE method
switch(eventObject.button) { case 1: buttons.left = true; break; case 2: buttons.right = true; break; case 3: buttons.left = true; buttons.right = true; break; case 4: buttons.middle = true; break; case 5: buttons.left = true; buttons.middle = true; break; case 6: buttons.middle = true; buttons.right = true; break; case 7: buttons.left = true; buttons.middle = true; buttons.right = true; break; default: break; } } else { return false; } return buttons; } window['ADS']['getMouseButton'] = getMouseButton;
处理鼠标的位置:
function getPointerPositionInDocument(eventObject) { eventObject = eventObject || getEventObject(eventObject); var x = eventObject.pageX || (eventObject.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft)); var y= eventObject.pageY || (eventObject.clientY + (document.documentElement.scrollTop || document.body.scrollTop)); //x and y now contain the coordinates of the mouse relative to the document origin
return {'x':x,'y':y}; } window['ADS']['getPointerPositionInDocument'] = getPointerPositionInDocument;
function getKeyPressed(eventObject) { eventObject = eventObject || getEventObject(eventObject); var code = eventObject.keyCode; var value = String.fromCharCode(code); return {'code':code,'value':value}; } window['ADS']['getKeyPressed'] = getKeyPressed;