js学习笔记:事件——事件类型
web浏览器中可能发生的事件有很多类型。DOM3级事件规定了以下几类事件:
変动事件:当底层DOM结构发生变化时触发
除了这几类事件之外,HTML5也定义了一组事件,有些浏览器还会在DOM和BOM中实现其他专有事件。
UI事件指的是那些不一定与用户操作有关的事件。现有的UI事件如下:
多数这些事件都与window对象或表单控件相关。
不冒泡
不能取消默认事件
Javascript中最常用的一个事件就是load。当页面完全加载后(包括所有图像、Javascript文件、CSS文件等外部资源),就会触发window上面的load事件。
有两种定义onload事件处理程序的方法:
图像上面也可以触发load事件,无论是在DOM元素中的图像元素还是HTML中的图像元素。因此可以在HTML中为任何图像指定onload事件处理程序:
<img src="smile.gif" onload="alert('image loaded')">
当然,同样的功能也可以用javascript完成。
在创建新的< img>元素时,可以为其指定一个事件处理程序,以便图像加载完毕后给出提示。此时,最重要的是要在指定src属性之前先指定事件。
EventUtil.addHandler(window,"load",function(){
var image = document.createElement("img");
EventUtil.addHandler(image,"load",function(event){
event = EventUtil.getEvent(event);
alert(EventUtil.getTarget(event).src);
});
document.body.appendChild(image);
image.src = "smile.gif";
})
上面例子中使用的EventUtil是之前定义的跨浏览器的定义事件处理程序和获取事件对象的接口。
这个例子中,首先为window指定了onload事件处理程序。原因在于,我们想向DOM中添加一个新元素,所以必须确定页面已经加载完毕——如果在页面加载前操作document.body会导致错误。
然后,创建了一个新的图像元素,并设置了其onload事件处理程序。
最后将这个图像添加到页面中,还设置了它的src属性。这里有一点要额外注意,新图像元素不一定要从添加到文档后才开始下载,只要设置了src属性就会开始下载。
还有一些元素也以非标准的方式支持load事件:
< script>元素也会触发load事件,以便开发人员确定动态加载的javascript文件是否加载完毕。
与图像不同,只有在设置了< script>元素的src属性并将该元素添加到文档后,才会开始下载Javascript文件。换句话说,对于< script>元素而言,指定src属性和指定事件处理程序的先后顺序就不重要了。
EventUtil.addHandler(window,"load",function(){
var script= document.createElement("script");
EventUtil.addHandler(script,"load",function(event){
alert("loaded");
});
script.src = "example.js";
document.body.appendChild(script);
})
IE和Opera还支持< link>元素上的load事件,以便开发人员确定样式表是否加载完毕。
与< script>节点类似,在未指定href属性并将< link>元素添加到文档之前也不会开始下载样式表。
不冒泡
不能取消默认事件
与load事件对应的是unload事件,这个事件在文档被完全卸载后触发。只要用户从一个页面切换到另一个页面,就会发生unload事件。而利用这个事件最多的情况就是清除引用,以避免内存泄露。
与load事件类似,也有两种指定onunload事件处理程序的方式:
此时event.target = document。
无论使用哪种方式,都要小心编写onunload事件处理程序中的代码。既然unload事件是在一切都被卸载之后才触发,那么在页面加载后存在的那些对象,此时就不一定存在了。此时,操作DOM节点或者元素的样式就会导致错误。
unload事件会在beforeunload事件之后被触发,而beforeunload事件是可以取消默认行为的。
不冒泡
不能取消默认事件
当浏览器窗口被调整到一个新的高度或宽度时,就会触发resize事件。这个事件在window上面触发,因此可以通过Javascript或者< body>元素中的onresize特性来指定事件处理程序。
EventUtil.addHandler(window,"resize",function(event){
alert("resize");
});
此时event.target = document。
关于何时会触发resize事件,不同的浏览器有不同的机制:
由于存在这个差别,应该注意不要在这个事件的处理程序中加入大计算量的代码,因为这些代码有可能被频繁执行,从而导致浏览器反应明显变慢。
浏览器窗口最小化或最大化时也会触发resize事件。
针对resize事件需要做防抖动或者节流处理:
var throttle = function(func,delay){
var timer = null;
return function(){
if(!timer){
timer = setTimeout(function(){
func();
timer = null;
},delay);
}
}
}
window.addEventListener("resize",throttle(handler,1000));
function handler(){
console.log(Date.now());
}
这样可以保证至少每一秒才触发一次。
也可以使用requestAnimationFrame来实现,使其在每一个渲染帧刷新一次。
var throttle = function(func,delay){
var running = false;
return function(){
if(!running){
running = true;
requestAnimationFrame(function(){
func();
running= false;
});
}
}
}
element的scroll事件不冒泡,但是document的defaultView的scroll事件冒泡
不能取消默认行为
虽然scroll事件是在window对象上发生的,但它实际表示的则是页面中相应元素的变化。
与resize事件类似,scroll事件也会在文档被滚动期间重复被触发,所以有必要尽量保持事件处理程序的代码简单。
移动端兼容性:在IOS系统中,视图滚动过程中scroll事件不会被触发,在滚动结束后scroll才会触发,因此移动端很少使用scroll事件。
都不能取消默认事件
焦点事件会在页面元素获得或失去焦点时触发。利用这些事件并与document.hasFocus()方法及document.activeElement属性配合,可以知晓用户在页面上的行踪。
有以下6个焦点事件:
这一类事件中最主要的两个是focus和blur,他们都是js早起就得到所有浏览器支持的事件,但它们不冒泡,因此才会有focusin和focusout被纳入标准。
当焦点从页面的一个元素移动到另一个元素,会依次触发下列事件:
其中,focusout和blur的事件目标是失去焦点的元素;focus和focusin的事件目标是获得焦点的元素。
鼠标事件是web开发中最常用的一类事件。DOM3级事件中定义了9个鼠标事件:
页面上所有元素都支持鼠标事件。除了mouseenter和mouseleave,所有鼠标事件都会冒泡,也可以被取消。
只有在同一个元素上相继触发mousedown和mouseup事件,才会触发click事件;
如果mousedown或mouseup中的一个被取消,就不会触发click事件。
类似的,只有触发两次click事件,才会触发一次dbclick事件。
如果有代码阻止了连续两次触发click事件,那么就不会触发dbclick事件了。
这4个事件的触发顺序始终如下:
显然,click和dbclick都会依赖与其他先行事件的触发;而mousedown和mouseup则不受其他事件影响。
另外注意mouseleave和mouseout的区别,之前写过一篇:mouseleave 与 mouseout 的不同
鼠标事件中还有一类滚轮事件mousewheel,这个事件跟踪鼠标滚轮。
鼠标事件都是在浏览器视口中的特定位置上发生的。这个位置信息保存在事件对象的clientX和clientY属性中。
所有浏览器都支持这两个属性,它们的值表示事件发生时鼠标指针在视口中的水平和垂直坐标。
通过客户区坐标能知道鼠标是在视口中什么位置发生的,而页面坐标通过事件对象的pageX和pageY属性,能告诉你事件是在页面中的什么位置发生的。
换句话说,pageX和pageY表示鼠标光标在页面中的位置,因此坐标是从页面本身而非视口的左边和顶边计算的。
在页面没有滚动的情况下,pageX和pageY的值与clientX和clientY的值相等。
鼠标事件发生时,不仅会有相对于浏览器窗口的位置,还有一个相对于整个电脑屏幕的位置。
通过screenX和screenY属性就可以确定鼠标事件发生时鼠标指针相对于整个屏幕的坐标信息。
虽然鼠标事件主要是使用鼠标来触发的,但在按下鼠标时键盘上的某些键的状态也可以影响到所要采取的操作。
这些修改键就是shift、ctrl、alt、meta。他们经常被用来修改鼠标事件的行为。
DOM为此规定了事件对象的4个属性,表示这些修改键的状态:shiftKey、ctrlKey、altKey、metaKey。这些属性中包含的都是布尔值,如果相应的键被按下了,则值为true,否则值为false。当某个鼠标事件发生时,通过检测这几个属性就可以确定用户是否同时按下了其中的键。
发生mouseover和mouseout事件时,还会涉及更多的元素。
这两个事件都会涉及把鼠标指针从一个元素的边界之内移动到另一个元素的边界之内。
来看下面这个例子:
<body>
<div id="myDiv">div>
body>
如果鼠标指针一开始位于这个< div>元素上,然后移除这个元素,那么就会在div元素上触发mouseout事件,相关元素就是< body>元素。与此同时,< body>元素上面会触发mouseover事件,而相关元素变成了< div>。
DOM通过event对象的relatedTarget属性提供了相关元素的信息。这个属性只对于mouseover、mouseout、mouseenter、mouseleave事件才包含值;对于其他事件,这个值为null。
IE8及之前版本不支持relatedTarget属性,但提供了保存着同样信息的不同属性:
只有在主鼠标按钮被单击时才会触发click事件,因此检测按钮的信息并不是必要的。
但对于mousedown和mouseup事件来说,则在其event对象存在一个button属性,表示按下或释放的按钮。
DOM的buttom属性可能有如下3个值:
DOM2级事件规范在event对象中还提供了detail属性,用于给出有关事件的更多信息。
对于鼠标事件来说,detail中包含了一个数值,表示在给定位置上发生过多少次单击。
在同一个元素上相继地发生一次mousedown和mouseup事件算一次单击。
detail属性从1开始计数,每次单击发生后都会递增。如果鼠标在mousedown和mouseup之间移动了位置,则detail会被重置为0.
当用户通过鼠标滚轮与页面交互,在垂直方向上滚动页面时,就会触发wheel事件。
这个事件可以在任何元素上面触发,最终会冒泡到document或window对象。
与wheel事件对应的event对象除了包含鼠标事件的所有标准信息外,还包含几个属性用来获取各个方向上滚动的距离:
将mousewheel事件处理程序指定给页面中的任何元素或document对象,即可处理鼠标滚轮的交互操作。
EventUtil.addHandler(document,"mousewheel",function(event){
event = EventUtil.getEvent(event);
alert(event.deltaY);
});
这个例子会在发生wheel事件时显示deltaY的值。
可以通过键盘上的回车键触发click事件,但其他鼠标事件却无法通过键盘来触发。为此,不建议使用click之外的鼠标事件来展示功能或引发代码执行,因为这样会给盲人或视障用户造成极大不便。
虽然所有元素都支持以上3个事件,但只有在用户通过文本框输入文本时才最常用到。
只有一个文本事件:textInput。这个事件是对keypress的补充,用意是在将文本显示给用户之前更容易拦截文本。在文本插入文本框之前会触发textInput事件。
用户按了一下键盘上的字符键时:
其中,keydown和keypress都是在文本框发生变化之前被触发的;keyup则是在文本框已经发生变化之后被触发的。
如果用户按下一个字符键不放,就会重复触发keydown和keypress事件,直到用户松开该键为止。
如果用户按下的是一个非字符键,那么首先会触发keydown事件,然后就是keyup事件。如果用户按住这个非字符键不放,就会重复触发keydown事件,直到用户松开该键为止,此时会触发keyup事件。
在发生keydown和keyup事件时,event对象的keyCode属性(或者key属性)中会包含一个代码,与键盘上的一个特定的键对应。
对于数字字母字符键,keyCode属性的值与ASCII码中对应小写字母或数字的编码相同。
DOM和IE的event对象都支持keyCode属性。
发生keypress事件意味着按下的键会影响屏幕中文本的显示。在所有浏览器中,按下能够查汝或删除字符的键都会触发keypress事件。
大多数浏览器的event对象都支持一个charCode属性(或者char属性),这个属性只有在发生keypress事件时才有值,而且这个值是按下的那个键所代表字符的ASCII编码。
在取得了字符编码之后,就可以使用String.fromCharCode()将其转换成实际的字符、
根据规范,当用户在可编辑区域中输入字符时,就会触发这个事件。这个用于替代keypress的textInput事件的行为稍有不同。
由于textInput事件主要考虑的是字符,因此它的event对象中还包含了一个data属性,这个属性的值就是用户输入的字符(而非字符编码)。
一个完整的drag and drop流程通常包含以下几个步骤:
draggable=true
,实现元素可拖拽dragstart:拖拽开始时在被拖拽元素上触发此事件,监听器需要设置拖拽所需数据。
从操作系统拖拽文件到浏览器时不触发此事件.
dragenter:拖拽鼠标进入元素时在该元素上触发,用于给拖放元素设置视觉反馈,如高亮
拖拽事件对象为DragEvent,此接口有一个dataTransfer属性,此属性值为一个对象,该对象包含了拖拽事件的状态、拖动事件的类型,拖动的数据等。
dropEffect:拖拽交互类型,可能的值:
effectAllowed:指定允许的交互类型,可以取值:copy,move,link,copyLink,copyMove,limkMove, all, none