事件(event)
- 事件就是 web 浏览器通知应用程序发生了什么事情。事件是可以被 javascript 侦测到的行为。
- 事件类型(event type)是一个用来说明发生什么类型事件的字符串。由于事件类型只是一个字符串,因此实际上有时会称之为事件名字(event name)。
- 事件目标(event target)是发生的事件或与之相关的对象。
- 事件处理程序(event handler)或事件监听程序(event listener)是处理或响应事件的函数。应用程序通过指明事件类型和事件目标,在 web 浏览器中注册它们的事件处理程序函数。
- 事件对象(event object)是与特定事件相关且包含有关该事件详细信息的对象。
- 事件传播(event propagation)是浏览器决定哪个对象触发其事件处理函数的过程。
事件类型(event type)
- 传统事件类型
- 表单事件
- submit 事件:提交按钮(``)被点击。
- reset 事件:重置按钮(``)被点击。
- focus 事件:元素获得焦点。
- blur 事件:元素失去焦点。
- change 事件:改变域的内容。
- window 事件
- load 事件:某个页面或图像被完成加载。
- unload 事件:用户退出页面。
- beforeunload:在即将离开当前页面(刷新或者关闭)是执行。
- error 事件:当加载文档或图像时发生某个错误。
- resize 事件:窗口或框架被调整尺寸。
- scroll 事件:元素滚动条滚动。
- 鼠标事件
- mousemove 事件:鼠标被移动或拖动鼠标。
- mouseout 事件:鼠标不再悬停到某个元素上。
- mousedown 事件:鼠标按下。
- mouseup 事件:鼠标释放。
- click 事件:单击鼠标按键。
- dblclick 事件:短时间连续两次单击(双击)鼠标按键。
- 键盘事件
- keydown 事件:某个键被按下。
- keyup 事件:某个键被松开。
- keypress 事件:某个键被按下或按住。
- DOM 事件
- HTML5 事件
HTML5及相关标准定义了大量的新的 web 应用 api。
广泛推广的HTML5特性之一是加入用于播放音频和视频的和
元素。这些元素有着长长的事件列表,他们触发各种关于网络事件、数据缓冲状况和播放状态的通知。
拖放事件:
- 触摸屏和移动设备事件
- 手势事件 gesture
- gesturestart 事件:手势生成。
- gesturechange 事件:手势过程。
- gestureend 事件:手势结束。
- 触摸事件 touch
- touchstart 事件:手指触摸屏幕。
- touchmove 事件:手指移动。
- touchend 事件:手指离开。
- 横竖屏切换 orientation
- orientationchange 事件:竖屏旋转到横屏模式。
window 对象的 orientation 属性能给出当前方位,其值是 0,90,180,-90。
注册事件处理程序
- 设置 javascript 对象属性为事件处理程序
事件处理程序属性的名字由 “on” 后面跟着事件名组成:onclick、 onchange、 onload、 onmouseover 等。
window.onload = funciton () {
var elt = document.getElementById("shipping_address");
elt.onsubmit = function () {
return validate(this);
}
}
- 设置 HTML 标签属性为事件处理程序
设置的文档元素事件处理程序属性(property)也能换成对应 HTML 标签的属性(attribute)。
- addEventListener()
除 IE8 及之前版本外的所有浏览器都支持。
addEventListener() 接收三个参数。第一个是要注册处理程序的事件类型(不包括 on );第二个参数是当指定类型的事件发生时应该调用的函数。最后一个参数是布尔值。通常情况下,会给这个参数传递 false。如果相反传递了 true,那么函数将注册为捕获事件处理程序,并在事件不同的调度阶段调用。
var b = document.getElementById("mybutton");
b.addEventListener("click", function() { alert("thanks!")}, false);
document.removeEventListener("mousemove", handleMouseMove, true);
- attachEvent
IE9 之前的 IE 不支持 addEventListener() 和 removeEventListener()。
IE5 及以后版本定义了类似的方法 attachEvent() 和 detachEvent()。
- addEventListener()、 removeEventListener() 和 attachEvent()、 detachEvent() 区别
- 因为 IE 事件模型不支持事件捕获,所以 attachEvent() 和 detachEvent() 要求只有两个参数:事件类型和处理程序函数。
- IE 方法的第一个参数使用了带 “on” 前缀的事件处理程序属性名。而非没有前缀的事件类型。
- attachEvent() 允许相同的事件处理函数注册多次。当特定的事件类型发生时,注册函数的调用次数和注册次数一样。
- this的区别
addEventLisener:事件处理程序会在当前对象的作用域运行,因此,事件处理程序的 this 就是当前对象。
attachEvent:事件处理程序是在全局作用域下运行因此 this 就是 window 。
var b = document.getElementById("mybutton");
var handler = function () {
alert("thanks");
};
if (b.addEventListener) {
b.addEventListener("click", handler, false);
} else if (b.attachEvent) {
b.attachEvent("onclick", handler);
}
移除事件的兼容写法:
var EventTools={
removeEventListener:function (element,eventName,listener) {
if(element.removeEventListener){
element.removeEventListener(eventName,listener,false);
}else if(element.detachEvent){
element.detachEvent("on"+eventName,listener);
}else{
element["on"+eventName]=null;
}
}
};
事件传播
事件传播的三个阶段
- 捕获
- 目标:正在执行当前对象的事件处理程序。
- 冒泡
事件捕获和事件冒泡
-
事件冒泡
如果元素 A 嵌套在元素 B 中,那么 A 被点击不仅 A 的 onclick 事件会被触发,B 的 onclick 也会被触发。触发的顺序是“由内而外” 。
- 取消事件冒泡:
window.event.cancelBubble = true;//IE
e.stopPropagation();
- 如何阻止事件冒泡和默认事件?
//阻止浏览器的默认行为
window.event?window.event.returnValue = false : e.preventDefault();
//停止事件冒泡
window.event?window.event.cancelBubble = true : e.stopPropagation();
原生 JavaScript 中,return false;
只阻止默认行为,不阻止冒泡,jQuery 中的 return false;
既阻止默认行为,又阻止冒泡。
-
事件捕获
和事件冒泡正好相反,逐级向下传播,触发的顺序是“由外而内”
其他
事件代理/委托的原理以及优缺点
- 原理:靠事件的冒泡机制来实现。让自己所触发的事件由他的父元素代替执行。
- 优点:可以大量节省内存占用,减少事件注册。可以实现当新增子对象时无需再次对其绑定事件,对于动态内容部分尤为合适。
- 缺点:事件代理的应用常用应该仅限上述需求下,如果把所有的事件都代理就可能出现事件误判,即本不应用触发事件的被绑上了事件(有人把页面里所有的时间都绑定到 document 用委托的,只是及其不智的做法)
实现事件代理,要求兼容浏览
// ============ 简单的事件委托
function delegateEvent(interfaceEle, selector, type, fn) {
if(interfaceEle.addEventListener){
interfaceEle.addEventListener(type, eventfn);
}else{
interfaceEle.attachEvent("on"+type, eventfn);
}
function eventfn(e){
var e = e || window.event;
var target = e.target || e.srcElement;
//如果目标元素与选择器匹配则执行函数
if (matchSelector(target, selector)) {
if(fn) {
//将fn内部的this指向target(在此之前this都是指向的绑定事件的元素即interfaceEle)
fn.call(target, e);
}
}
}
}
/**
* only support #id, tagName, .className
* and it's simple single, no combination
*/
//比较函数:判断事件的作用目标是否与选择器匹配;匹配则返回true
function matchSelector(ele, selector) {
// 如果选择器为ID
if (selector.charAt(0) === "#") {
return ele.id === selector.slice(1);
}
//charAt(0),返回索引为0的字符
//slice(a,b),从已有的数组或字符串返回从索引从a处开始,截取到索引b之前的子数组或子字符串;
//如果选择器为Class
if (selector.charAt(0) === ".") {
return (" " + ele.className + " ").indexOf(" " + selector.slice(1) + " ") != -1;
}
// 如果选择器为tagName
return ele.tagName.toLowerCase() === selector.toLowerCase();
}
//toLowerCase()将字符串转换成小写
//调用
var odiv = document.getElementById("oDiv");
delegateEvent(odiv,"a","click",function(){
alert("1");
})
参考自:
javascript权威指南
1.事件委托的原理以及优缺点 2. 手写原生js实现事件代理,并要求兼容浏览器