• 一、事件流

我们通过下面一个实例,进行说明。

<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的时候,也单击了其祖先列表

  • 事件冒泡--

  • 事件捕获--

  • W3C捕获以及冒泡事件流

阻止冒泡

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>
  • 深入理解ADS.addEvent()方法
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 DOM2事件模型
//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事件

无论那种事件注册方法,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;

跨浏览器的事件属性和方法

  • W3C DOM2事件模型为Event对象

定义了下列属性。

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);
});
  • 确定单击了哪个鼠标键(下面代码直接copy源代码的。不高兴敲了)
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;

JavaScript DOM高级程序设计 4.3控制事件流和注册事件侦听器--我要坚持到底!的更多相关文章

  1. JavaScript DOM 高级程序设计读书笔记二

    响应用户操作和事件 事件就是操作检测与脚本执行的组合,或者基于检测到的操作类型在某个对象上调用事件侦听器(事件处理程序). 事件的类型 事件可以分为几种类型:对象事件,鼠标事件,键盘事件(只适用于do ...

  2. 异常将上下文初始化事件发送到类的侦听器实例.[org.springframework.web.context.ContextLoaderListener] org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class p

    严重: 异常将上下文初始化事件发送到类的侦听器实例.[org.springframework.web.context.ContextLoaderListener]org.springframework ...

  3. JavaScript DOM高级程序设计 4.2 事件类型--我要坚持到底!

    对象事件 load和unload(载入页面的时候调用load,关闭页面的时候调用unload) abort和error 对于载入图像时出现错误的情况,可以使用error事件侦听器来进行说明: ADS. ...

  4. JavaScript DOM高级程序设计 3.6 实例 将HTML代码转换成DOM代码(附源码)--我要坚持到底!

    作为一名Web开发者,最讨厌的事情就是重复性任务,摆脱乏味的日常重复性事物的一种方法,是借助可重用的对象或者说与你现在建立的ADS库类似的库,另外一种让事情变得有意思,且能够加速开发进程的方式是编写能 ...

  5. JavaScript DOM高级程序设计 5动态修改样式和层叠样式表2--我要坚持到底!

    把样式置于DOM脚本之外 style属性 我们可以这样设置前景色之类的属性: element.style.color='red'; 也可以使用下面的代码设置背景颜色: element.style.ba ...

  6. JavaScript DOM高级程序设计1.2-循序最佳实践--我要坚持到底!

    我这人,最大的毛病就是浮躁. 下面开始我再一次的学习之旅,希望我能坚持到最后.记笔记除了分享以外,更重要的是让自己看见自己学习之路. 先把ADS库贴出来http://vdisk.weibo.com/s ...

  7. JavaScript DOM高级程序设计 7.向应用程序加入Ajax--我要坚持到底!

    有时候,或许是因为理解能力,也或许是因为浮躁,看东西总是不入心,而且还老是想跳过本节,或者赶紧看完本节,这样的恶性循环,让我在即没有真正的学习到知识,又打击我的学习信心,还浪费了我很多事件,我想,当遇 ...

  8. JavaScript DOM高级程序设计 5动态修改样式和层叠样式表1(源代码)--我要坚持到底!

    W3C DOM2样式规范 现在这边贴出本章要的源代码,注意要结合前面用到的ADS库http://vdisk.weibo.com/s/Dq8NU CSSStyleSheet对象属性: type :始终是 ...

  9. JavaScript DOM高级程序设计 3.-DOM2和HTML2--我要坚持到底!

    由一个HTML进行说明,我就不敲了,直接copy <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" " ...

随机推荐

  1. jquery ListBox 左右移动

    <head runat="server"> <title>无标题页</title> <script type="text/jav ...

  2. log4net基本日志使用笔记[windows application]

    Ref: http://www.cnblogs.com/wangsaiming/archive/2013/01/11/2856253.html http://www.cnblogs.com/zhouf ...

  3. SQL行列转换:报表_公司采购表_每个公司各采购了些什么产品

    有同学问了个比较典型行列转换的问题,想想,解答如下:数据库有一张表: 是个公司采购表,想转化成如下报表,显示每个公司各采购了些什么产品: 哪些公司采购哪些产品是不确定的,所以报表的列有哪几项是不确定的 ...

  4. Apache多站点设定

    多端口 vi httpd.conf Listen 8090 <VirtualHost *:8090> ServerName localhost Documentroot "/Us ...

  5. what is the purpose of channel coding?(信道编码的作用?)

    信道.信道编码及其作用 1.信道(channel) 信道和通信电路并不等同,用来表示向某一个方向传送信息的媒体.因此一条通信线路往往包含一条发送信道和一条接收信道. 从通信的双方信息交互方式看有三个基 ...

  6. 字符串转换成整型数 atoi()

    题目说明: 1.设计函数: int atoi(const char *nptr); 2.功能:把字符串转换成整型数,atoi()会扫描参数nptr字符串,如果第一个非空格字符存在, 是数字或者正负号则 ...

  7. (转)《深入理解java虚拟机》学习笔记7——Java虚拟机类生命周期

    C/C++等纯编译语言从源码到最终执行一般要经历:编译.连接和运行三个阶段,连接是在编译期间完成,而java在编译期间仅仅是将源码编译为Java虚拟机可以识别的字节码Class类文件,Java虚拟机对 ...

  8. 拉链法解决Hash节点冲突问题

    <?php /* * hash::拉链法解决hash节点存储冲突问题 * ::2014-07-02 * ::Small_Kind */ class small_hash { private $s ...

  9. PHP webserver 之 soap 生成wsdl文件

    <?php /** * Copyright (c) , Braulio Jos?Solano Rojas * All rights reserved. * * Redistribution an ...

  10. MINA快速传输文件

    最近的项目使用MNA进行文件传输,只能传输到5~7MB/s:但是使用FTP等软件其实可以达到11MB/s,后来使用MINA原生传输,发现可以达到11MB/s,后来发现有以下两点可以需要注意优化: 1. ...