JavaScript高级程序设计学习13_事件

1、事件对象

兼容 DOM 的浏览器会将一个 event 对象传入到事件处理程序中。无论指定事件处理程序时使用什么方法( DOM0 级或 DOM2 级),都会传入 event 对象。触发的事件类型不一样,可用的属性和方法也不一样。不过,所有事件都会有下表列出的成员。

虽然 DOM 和 IE 中的 event 对象不同,但基于它们之间的相似性依旧可以拿出跨浏览器的方案来。IE 中 event 对象的全部信息和方法 DOM 对象中都有,只不过实现方式不一样。不过,这种对应关系让实现两种事件模型之间的映射非常容易。可以对前面介绍的 EventUtil 对象加以增强,添加如下方法以求同存异。

var EventUtil = {
  addHandler: function(element, type, handler){
    //省略的代码
  },
  getEvent: function(event){
    return event ? event : window.event;
  },
  getTarget: function(event){
    return event.target || event.srcElement;
  },
  preventDefault: function(event){
    if (event.preventDefault){
      event.preventDefault();
    } else {
      event.returnValue = false;
    }
  },
  removeHandler: function(element, type, handler){
    //省略的代码
  },
  stopPropagation: function(event){
    if (event.stopPropagation){
      event.stopPropagation();
    } else {
      event.cancelBubble = true;
    }
  }
};
//调用对象示例stopPropagation()
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
  alert("Clicked");
  event = EventUtil.getEvent(event);
  EventUtil.stopPropagation(event);
};
document.body.onclick = function(event){
  alert("Body clicked");
};

2、事件类型

1、UI事件

UI 事件指的是那些不一定与用户操作有关的事件。

 load:当页面完全加载后在 window 上面触发,当所有框架都加载完毕时在框架集上面触发,当图像加载完毕时在<img>元素上面触发,或者当嵌入的内容加载完毕时在<object>元素上面触发。
 unload:当页面完全卸载后在 window 上面触发,当所有框架都卸载后在框架集上面触发,或者当嵌入的内容卸载完毕后在<object>元素上面触发。
 abort:在用户停止下载过程时,如果嵌入的内容没有加载完,则在<object>元素上面触发。
 error:当发生 JavaScript 错误时在 window 上面触发,当无法加载图像时在<img>元素上面触发,当无法加载嵌入内容时在<object>元素上面触发,或者当有一或多个框架无法加载时在框架集上面触发。第 17 章将继续讨论这个事件。
 select:当用户选择文本框( <input>或<texterea>)中的一或多个字符时触发。第 14 章将继续讨论这个事件。
 resize:当窗口或框架的大小变化时在 window 或框架上面触发。
 scroll:当用户滚动带滚动条的元素中的内容时,在该元素上面触发。 <body>元素中包含所加载页面的滚动条。

2、焦点事件

焦点事件会在页面元素获得或失去焦点时触发。利用这些事件并与 document.hasFocus()方法及document.activeElement 属性配合,可以知晓用户在页面上的行踪。有以下 6 个焦点事件。

 blur:在元素失去焦点时触发。这个事件不会冒泡;所有浏览器都支持它。
 DOMFocusIn:在元素获得焦点时触发。这个事件与 HTML 事件 focus 等价,但它冒泡。只有Opera 支持这个事件。 DOM3 级事件废弃了 DOMFocusIn,选择了 focusin。
 DOMFocusOut:在元素失去焦点时触发。这个事件是 HTML 事件 blur 的通用版本。只有 Opera支持这个事件。 DOM3 级事件废弃了 DOMFocusOut,选择了 focusout
 focus:在元素获得焦点时触发。这个事件不会冒泡;所有浏览器都支持它。
 focusin:在元素获得焦点时触发。这个事件与 HTML 事件 focus 等价,但它冒泡。支持这个事件的浏览器有 IE5.5+、 Safari 5.1+、 Opera 11.5+和 Chrome。
 focusout:在元素失去焦点时触发。这个事件是 HTML 事件 blur 的通用版本。支持这个事件的浏览器有 IE5.5+、 Safari 5.1+、 Opera 11.5+和 Chrome。

3、鼠标与滚轮事件

 click:在用户单击主鼠标按钮(一般是左边的按钮)或者按下回车键时触发。这一点对确保易访问性很重要,意味着 onclick 事件处理程序既可以通过键盘也可以通过鼠标执行。
 dblclick:在用户双击主鼠标按钮(一般是左边的按钮)时触发。从技术上说,这个事件并不是 DOM2 级事件规范中规定的,但鉴于它得到了广泛支持,所以 DOM3 级事件将其纳入了标准。
 mousedown:在用户按下了任意鼠标按钮时触发。不能通过键盘触发这个事件。
 mouseenter:在鼠标光标从元素外部首次移动到元素范围之内时触发。这个事件不冒泡,而且在光标移动到后代元素上不会触发。 DOM2 级事件并没有定义这个事件,但 DOM3 级事件将它纳入了规范。 IE、 Firefox 9+和 Opera 支持这个事件。
 mouseleave:在位于元素上方的鼠标光标移动到元素范围之外时触发。这个事件不冒泡,而且在光标移动到后代元素上不会触发。 DOM2 级事件并没有定义这个事件,但 DOM3 级事件将它纳入了规范。 IE、 Firefox 9+和 Opera 支持这个事件。
 mousemove:当鼠标指针在元素内部移动时重复地触发。不能通过键盘触发这个事件。
 mouseout:在鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发。又移入的另一个元素可能位于前一个元素的外部,也可能是这个元素的子元素。不能通过键盘触发这个事件。
 mouseover:在鼠标指针位于一个元素外部,然后用户将其首次移入另一个元素边界之内时触发。不能通过键盘触发这个事件。
 mouseup:在用户释放鼠标按钮时触发。不能通过键盘触发这个事件。

注意:只有在同一个元素上相继触发 mousedown 和 mouseup 事件,才会触发 click 事件;如果mousedown 或 mouseup 中的一个被取消,就不会触发 click 事件。类似地,只有触发两次 click 事件, 才会触发一次 dblclick 事件。如果有代码阻止了连续两次触发 click 事件(可能是直接取消 click事件,也可能通过取消 mousedown 或 mouseup 间接实现),那么就不会触发 dblclick 事件了。这 4个事件触发的顺序始终如下:
(1) mousedown
(2) mouseup
(3) click
(4) mousedown
(5) mouseup
(6) click
(7) dblclick
显然, click 和 dblclick 事件都会依赖于其他先行事件的触发;而 mousedown 和 mouseup 则不受其他事件的影响。

鼠标事件中还有一类滚轮事件。而说是一类事件,其实就是一个 mousewheel 事件。这个事件跟踪鼠标滚轮,类似于 Mac 的触控板。

3.1、客户区坐标位置

这个位置信息保存在事件对象的 clientX 和clientY 属性中

3.2、页面坐标位置

通过事件对象的 pageX 和pageY 属性,能告诉你事件是在页面中的什么位置发生的。

3.3、屏幕坐标位置

通过 screenX 和 screenY 属性就可以确定鼠标事件发生时鼠标指针相对于整个屏幕的坐标信息

3.4、修改键

这些修改键就是 Shift、 Ctrl、 Alt 和 Meta(在 Windows 键盘中是 Windows 键,在苹果机中是 Cmd 键),它们经常被用来修改鼠标事件的行为。 DOM 为此规定了 4 个属性,表示这些修改键的状态: shiftKey、 ctrlKey、 altKey 和 metaKey。这些属性中包含的都是布尔值,如果相应的键被按下了,则值为 true,否则值为 false。当某个鼠标事件发生时,通过检测这几个属性就可以确定用户是否同时按下了其中的键。来看下面的例子:

var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event){
  event = EventUtil.getEvent(event);
  var keys = new Array();
  if (event.shiftKey) keys.push("shift");
  if (event.ctrlKey) keys.push("ctrl");
  if (event.altKey) keys.push("alt");
  if (event.metaKey) keys.push("meta");
  alert("Keys: " + keys.join(","));
});

3.5、鼠标按钮

对于 mousedown 和 mouseup 事件来说,则在其 event 对象存在一个 button 属性,表示按下或释放的按钮。 DOM 的 button 属性可能有如下 3 个值: 0 表示主鼠标按钮, 1 表示中间的鼠标按钮(鼠标滚轮按钮), 2 表示次鼠标按钮。

3.6、更多的事件信息

“DOM2 级事件”规范在 event 对象中还提供了 detail 属性,用于给出有关事件的更多信息。对于鼠标事件来说, detail 中包含了一个数值,表示在给定位置上发生了多少次单击。在同一个元素上相继地发生一次 mousedown 和一次 mouseup 事件算作一次单击。 detail 属性从 1 开始计数,每次单击发生后都会递增。如果鼠标在 mousedown 和 mouseup 之间移动了位置,则 detail 会被重置为 0。

3.7、鼠标滚轮事件

当用户通过鼠标滚轮与页面交互、在垂直方向上滚动页面时(无论向上还是向下),就会触发 mousewheel事件。这个事件可以在任何元素上面触发,最终会冒泡到 document( IE8)或 window( IE9、 Opera、Chrome 及 Safari)对象。与 mousewheel 事件对应的 event 对象除包含鼠标事件的所有标准信息外,还包含一个特殊的 wheelDelta 属性。当用户向前滚动鼠标滚轮时, wheelDelta 是 120 的倍数;当用户向后滚动鼠标滚轮时, wheelDelta 是120 的倍数。

element.addEventListener('mousewheel',function(evt){
  console.log(evt.wheelDelta);
});

3.8、触摸设备

iOS 和 Android 设备的实现非常特别,因为这些设备没有鼠标。在面向 iPhone 和 iPod 中的 Safari开发时,要记住以下几点。
 不支持 dblclick 事件。双击浏览器窗口会放大画面,而且没有办法改变该行为。
 轻击可单击元素会触发 mousemove 事件。如果此操作会导致内容变化,将不再有其他事件发生;如果屏幕没有因此变化,那么会依次发生 mousedown、 mouseup 和 click 事件。轻击不可单击的元素不会触发任何事件。可单击的元素是指那些单击可产生默认操作的元素(如链接),或者那些已经被指定了 onclick 事件处理程序的元素。
 mousemove 事件也会触发 mouseover 和 mouseout 事件。
 两个手指放在屏幕上且页面随手指移动而滚动时会触发 mousewheel 和 scroll 事件。

4、键盘和文本事件

4.1、在发生 keydown 和 keyup 事件时, event 对象的 keyCode 属性中会包含一个代码,与键盘上一个特定的键对应。对数字字母字符键, keyCode 属性的值与 ASCII 码中对应小写字母或数字的编码相同。因此,数字键 7 的 keyCode 值为 55,而字母 A 键的 keyCode 值为 65——与 Shift 键的状态无关。DOM 和 IE 的 event 对象都支持 keyCode 属性。请看下面这个例子:

var textbox = document.getElementById("myText");
textbox.addEventListener('keyup',function(evt){
  alert(event.keyCode);//显示当前键码
});

4.2、发生 keypress 事件(影响文本的键)意味着按下的键会影响到屏幕中文本的显示。在所有浏览器中,按下能够插入或删除字符的键都会触发 keypress 事件;按下其他键能否触发此事件因浏览器而异。

4.3、“DOM3 级事件”规范中引入了一个新事件,名叫 textInput。根据规范,当用户在可编辑区域中输入字符时,就会触发这个事件。这个用于替代 keypress 的 textInput 事件的行为稍有不同。区别之一就是任何可以获得焦点的元素都可以触发 keypress 事件,但只有可编辑区域才能触发 textInput事件。区别之二是 textInput 事件只会在用户按下能够输入实际字符的键时才会被触发,而 keypress事件则在按下那些能够影响文本显示的键时也会触发(例如退格键)。

    由于 textInput 事件主要考虑的是字符,因此它的 event 对象中还包含一个 data 属性,这个属性的值就是用户输入的字符(而非字符编码)。换句话说,用户在没有按上档键的情况下按下了 S 键,data 的值就是"s",而如果在按住上档键时按下该键, data 的值就是"S"。另外, event 对象上还有一个属性,叫 inputMethod,表示把文本输入到文本框中的方式。

5、变动事件

DOM2 级的变动( mutation)事件能在 DOM 中的某一部分发生变化时给出提示。变动事件是为 XML或 HTML DOM 设计的,并不特定于某种语言。 DOM2 级定义了如下变动事件。
 DOMSubtreeModified:在 DOM 结构中发生任何变化时触发。这个事件在其他任何事件触发后都会触发。
 DOMNodeInserted:在一个节点作为子节点被插入到另一个节点中时触发。
 DOMNodeRemoved:在节点从其父节点中被移除时触发。
 DOMNodeInsertedIntoDocument:在一个节点被直接插入文档或通过子树间接插入文档之后触发。这个事件在 DOMNodeInserted 之后触发。
 DOMNodeRemovedFromDocument:在一个节点被直接从文档中移除或通过子树间接从文档中移除之前触发。这个事件在DOMNodeRemoved 之后触发。
 DOMAttrModified:在特性被修改之后触发。
 DOMCharacterDataModified:在文本节点的值发生变化时触发。

6、HTML5事件

contextmenu事件:上下文菜单事件,可通过点击右键调出上下文菜单,由于这个事件是冒泡的,因此可以为document指定一个事件处理程序,用以处理页面中发生的所有此类事件,如下例:

/*html部分*/
/*<div id="myDiv" style="background-color:blue; width:100%; height:100%;">
</div>
<ul id="menu" style="position:absolute;visibility:hidden;background-color:solver;">
	<li>11111111111111111111111111</li>
	<li>11111111111111111111111111</li>
	<li>11111111111111111111111111</li>
</ul>*/

window.addEventListener('load',function(evt){
  var div = document.getElementById("myDiv");
				
  div.addEventListener('contextmenu',function(evt){
	evt.preventDefault();
					
	let menu = document.getElementById("menu");
	menu.style.left = evt.clientX + 'px';
	menu.style.top = evt.clientY + 'px';
	menu.style.visibility = "visible";
  });
				
  document.addEventListener('click',function(evt){
	document.getElementById("menu").style.visibility = "hidden";
  });
});

beforeunload事件:有可能在页面卸载前组织这一操作,如下例:

window.addEventListener('beforeunload',function(evt){
  let msg = "do you want to go?";
  evt.returnValue = msg;//对于IE和FireBox而言
  return msg;//对于Safari和Chrome而言
});

DOMContentLoaded事件:load事件会在页面中的一切都加载完毕触发,而DOMContentLoaded事件则在形成完整的DOM树之后就会出发,不理会其他文件是否下载完毕。

readystatechange事件:目的是提供与文档de或元素的加载状态有关的信息。

pageshow和pagehide事件:Firefox 和 Opera 有一个特性,名叫“往返缓存”( back-forward cache,或 bfcache),可以在用户使用浏览器的“后退”和“前进”按钮时加快页面的转换速度。这个缓存中不仅保存着页面数据,还保存了 DOM 和 JavaScript 的状态;实际上是将整个页面都保存在了内存里。如果页面位于 bfcache 中,那么再次打开该页面时就不会触发 load 事件。尽管由于内存中保存了整个页面的状态,不触发 load 事件也不应该会导致什么问题,但为了更形象地说明 bfcache 的行为, Firefox 还是提供了一些新事件。
        第一个事件就是 pageshow,这个事件在页面显示时触发,无论该页面是否来自 bfcache。在重新加载的页面中, pageshow 会在 load 事件触发后触发;而对于 bfcache 中的页面, pageshow 会在页面状态完全恢复的那一刻触发。另外要注意的是,虽然这个事件的目标是 document,但必须将其事件处理程序添加到 window。来看下面的例子。

window.addEventListener('load',function(evt){
  alert(111);
});
window.addEventListener('pageshow',function(evt){
  alert(222);
});//pagehide与之相反

haschange事件:HTML5 新增了 hashchange 事件,以便在 URL 的参数列表(及 URL 中“#”号后面的所有字符串)发生变化时通知开发人员。之所以新增这个事件,是因为在 Ajax 应用中,开发人员经常要利用 URL 参数列表来保存状态或导航信息。必须要把 hashchange 事件处理程序添加给 window 对象,然后 URL 参数列表只要变化就会调用它。此时的 event 对象应该额外包含两个属性: oldURL 和 newURL。这两个属性分别保存着参数列表变化前后的完整 URL。例如:

window.addEventListener('haschange',function(evt){
  alert("Old URL: " + evt.oldURL + "\nNew URL: " + evt.newURL);
  //最好使用location对象来确定当前的参数列表
  alert("Current hash:"+location.hash);
});

7、设备事件

orientationchange事件:以便开发人员能够确定用户何时将设备由横向查看模式切换为纵向查看模式。移动 Safari 的 window.orientation 属性中可能包含 3 个值:0 表示肖像模式, 90 表示向左旋转的横向模式(“主屏幕”按钮在右侧), -90 表示向右旋转的横向模式(“主屏幕”按钮在左侧)。相关文档中还提到一个值,即 180 表示 iPhone 头朝下;但这种模式至今尚未得到支持。

只要用户改变了设备的查看模式,就会触发此事件,但此时的event对象不包含任何有价值的信息,因为唯一的信息可以通过window.orientatio访问到。

window.addEventListener('load',function(evt){
  var div = document.getElementById("myDiv");
  div.innerHTML = "Current orientation is " + window.orientation;
  window.addEventListener('orientationchange',function(evt){
    var div = document.getElementById("myDiv");
    div.innerHTML = "Current orientation is " + window.orientation;
  });
});

MozOrientation事件:当设备的加速计监测到设备方向改变时,就会触发这个事件,与IOS不同的是orientationchange不同,该事件只能提供一个平面的方向变化。

deviceorientation事件:与MozOrientation类似,在window对象上触发,但意图是告诉开发人员朝哪儿,而不是如何移动。

devicemotion事件:这个事件告诉开发者设备什么时候移动,而不是仅仅方向如何改变。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值