事件流
1.事件冒泡
IE 的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,
然后逐级向上传播到较为不具体的节点(文档),最后到document。
2.事件捕获
Netscape Communicator 团队提出的另一种事件流叫做事件捕获(event capturing)。事件捕获的思想是不太具体的节点应该更早接收到事件,
而最具体的节点应该最后接收到事件。事件捕获的用意在于在事件到达预定目标之前捕获它。
3.DOM事件流
“DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段
首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应
IE 与火狐的事件机制有什么区别? 如何阻止冒泡?
IE 只事件冒泡,不支持事件捕获;火狐同时支持件冒泡和事件捕获。
阻止冒泡:
- 取消默认操作
- w3c 的方法是 e.preventDefault()
- IE 则是使用 e.returnValue = false;
- return false
- javascript 的 return false 只会阻止默认行为
- 是用 jQuery 的话则既阻止默认行为又防止对象冒泡。
- 阻止冒泡
- w3c 的方法是 e.stopPropagation()
- IE 则是使用 e.cancelBubble = true
[js] view plaincopy
function stopHandler(event)
window.event
? window.event.cancelBubble = true
: event.stopPropagation();
}
事件处理程序
1.DOM0级事件处理程序
DOM0级事件处理程序,只能在冒泡阶段被处理,并且不支持重复添加
var btn = document.getElementById("myBtn");
btn.onclick = function(){
// 函数中的 this 引用当前元素
alert("Clicked");
};
btn.onclick = null; //删除事件处理程序
2.DOM2 级事件处理程序
用于处理指定和删除事件处理程序的操作:addEventListener()和 removeEventListener()
三个参数,1事件名,2函数,3表示触发阶段的布尔值(为true表示在捕获阶段调用),可以添加多个事件处理程序,按顺序触发
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
alert(this.id);
}, false);
btn.addEventListener("click", function(){
alert("Hello world!");
}, false);
只能使用 removeEventListener()来移除,传递的参数必须相同,注意函数的指向必须是同一个函数(不能是匿名函数)
3.IE事件处理程序
IE 实现了与 DOM 中类似的两个方法:attachEvent()和 detachEvent()。
这两个方法接受相同的两个参数:事件处理程序名称与事件处理程序函数(IE只支持事件冒泡,被添加到冒泡阶段)
attachEvent()方法也可以用来为一个元素添加多个事件处理程序。不同的是,它是后添加的事件先执行
添加的事件可以通过 detachEvent()来移除,条件是必须提供相同的参数,不过第二个参数是相同的函数引用即可,注意添加事件名称前面有“on”
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
alert("Clicked");
});
//先执行绑定的第二个方法
btn.attachEvent("onclick", function(){
alert("Hello world!");
});
事件对象
在触发 DOM 上的某个事件时,会产生一个事件对象 event,这个对象中包含着所有与事件有关的信息。
包括导致事件的元素、事件的类型以及其他与特定事件相关的信息。
1.DOM中的事件对象
兼容 DOM 的浏览器会将一个 event 对象传入到事件处理程序中
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert(event.type); //"click"
};
btn.addEventListener("click", function(event){
alert(event.type); //"click"
}, false);
2.取消默认行为
preventDefault()来取消其默认行为
stopPropagation()方法用于立即停止事件在 DOM 层次中的传播,即取消进一步的事件捕获或冒泡
3.eventPhase 属性
eventPhase 属性,可以用来确定事件当前正位于事件流的哪个阶段。
- 如果是在捕获阶段调用的事件处理程序,那么 eventPhase 等于 1
- 如果事件处理程序处于目标对象上,则 eventPhase 等于 2
- 如果是在冒泡阶段调用的事件处理程序,eventPhase 等于 3
Event 对象常见应用
- event.target
- 触发事件的元素
- event.currentTarget
- 绑定事件的元素
- event.preventDefault()
- 阻止默认行为
- event.cancelBubble()和 event.preventBubble 都已经废弃
- event.stopPropagation()
- 阻止在捕获阶段或冒泡阶段继续传播,而不是阻止冒泡
- event.stopImmediatePropagation()
- 阻止事件冒泡并且阻止相同事件的其他侦听器被调用。
事件类型
1.UI事件
UI事件指的是那些不一定与用户操作有关的事件
load 事件
页面加载完毕时触发,只有 、、、<img>
、、
window.onload = function(){
alert('1234')
}
可以为图片标签(未成功)或者body标签添加onload属性,新图像元素不一定要从添加到文档后才开始下载,只要设置了 src 属性就会开始下载。
document.getElementById("myImg").onload = function(){
alert("456");
}
与图像不同,只有在设置了
DOMContentLoaded 事件
如前所述,window 的 load 事件会在页面中的一切都加载完毕时触发,但这个过程可能会因为要加载的外部资源过多而颇费周折。
而 DOMContentLoaded 事件则在形成完整的 DOM 树之后就会触发,不理会图像、JavaScript 文件、CSS 文件或其他资源是否已经下载完毕。
与 load 事件不同, DOMContentLoaded 支支持在页面下载的早期添加事件处理程序,这也就意味着用户能够尽早地与页面进行交互。
unload事件
这个事件在文档被完全卸载后触发。只要用户从一个页面切换到另一个页面,就会发生 unload 事件。
而利用这个事件最多的情况是清除引用,以及事件绑定,以避免内存泄漏。
onbeforeunload事件
页面有更改后,在刷新和退出时触发(很多公司官网会用这个来提醒用户)
window.onbeforeunload = function(event) {
// 须将 event.returnValue 的值设置为要显示给用户的字符串
var msg = "Are you sure you want to leave?";
event.returnValue = msg;
return msg;
};
resize事件
窗口缩放的时候,在window窗口触发
scroll事件
滚动条滑动的时候触发
2.焦点事件
这些事件在绑定和调用的时候前面会加上 on
focusout
在失去焦点的元素上触发;
focusin
在获得焦点的元素上触发;
blur
在失去焦点的元素上触发;不会冒泡
focus
在获得焦点的元素上触发;不会冒泡
3.鼠标事件
var isSupported = document.implementation.hasFeature(“MouseEvent”, “3.0”)
检测浏览器是否支持3.0的鼠标事件
click
在用户单击主鼠标按钮(一般是左边的按钮)或者按下回车键时触发。
dblclick
在用户双击主鼠标按钮(一般是左边的按钮)时触发。
mousedown
在用户按下了任意鼠标按钮时触发。不能通过键盘触发这个事件。
mouseup
在用户释放鼠标按钮时触发。不能通过键盘触发这个事件。
mouseenter
在鼠标光标从元素外部首次移动到元素范围之内时触发。不冒泡,在光标移动到后代元素上不会触发.
mouseleave
在位于元素上方的鼠标光标移动到元素范围之外时触发。不冒泡,在光标移动到后代元素上不会触发。
mouseout
在鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发。又移入的另一个元素可能位于前一个元素的外部,也可能是这个元素的子元素。不能通过键盘触发这个事件。
mousemove
当鼠标指针在元素内部移动时重复地触发。不能通过键盘触发这个事件。
mouseover
在鼠标指针位于元素外部,然后用户将其首次移入元素边界之内时触发。不能通过键盘触发这个事件。
检测鼠标在发生点击的位置
document.getElementById("div1").onclick = function(event){
// 鼠标在元素中的位置
alert("Client coordinates: " + event.clientX + "," + event.clientY);
// 鼠标在浏览器页面中的位置
alert("Page coordinates: " + event.pageX + "," + event.pageY);
// 鼠标在电脑窗口中的位置
alert("Screen coordinates: " + event.screenX + "," + event.screenY);
}
鼠标滚轮事件
当用户通过鼠标滚轮与页面交互、在垂直方向上滚动页面时(无论向上还是向下),就会触发 mousewheel事件。这个事件可以在任何元素上面触发,最终会冒泡到 document(IE8)或 window(IE9、Opera、Chrome 及 Safari)对象。
wheelDelta属性记录了用户滚动的距离,当用户向前滚动滚轮时,wheelDelta变化是120的倍数
4.键盘与文本事件
keydown
当用户按下键盘上的任意键时触发,而且如果按住不放的话,会重复触发此事件。
document.onkeydown = function(event){
//按下不同的键,对应不同的键码
console.log(event.keyCode);
}
keypress
当用户按下键盘上的字符键时触发,而且如果按住不放的话,会重复触发此事件。按下 Esc 键也会触发这个事件。
keyup
当用户释放键盘上的键时触发。
textInput
在文本插入文本框之前会触发,是任何可以获得焦点的元素都可以触发 keypress 事件,但只有可编辑区域才能触发 textInput
5.HTML5 事件
contextmenu 事件
通过鼠标右键点击事件调出的上下文菜单,通过这样,我们可以自定义右键点击出现的菜单列表
window.onload = function(event){
var div = document.getElementById("myDiv");
div.oncontextmenu = function(event){
event.preventDefault();
var menu = document.getElementById("myMenu");
//鼠标点击处的右下方
menu.style.left = event.clientX + "px";
menu.style.top = event.clientY + "px";
menu.style.visibility = "visible";
};
document.onclick = function(event){
document.getElementById("myMenu").style.visibility = "hidden";
};
};
hashchange 事件
HTML5 新增了 hashchange 事件,以便在 URL 的参数列表(及 URL 中“#”号后面的所有字符串)发生变化时通知开发人员。
window.onhashchange=function(event){
alert("Current hash: " + location.hash);
};
事件委托/事件代理
原理:
只指定一个事件处理程序,就可以管理某一类型的所有事件。例如,click 事件会一直冒泡到 document 层次
采用事件委托技术的事件包括 click、mousedown、mouseup、keydown、keyup 和 keypress。
使用事件委托,只需在DOM 树中尽量最高的层次上添加一个事件处理程序,便能监听一类事件。
优点:
在JavaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断的与dom节点进行交互,访问dom的次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间,这就是为什么性能优化的主要思想之一就是减少DOM操作的原因;如果要用事件委托,就会将所有的操作放到js程序里面,与dom的操作就只需要交互一次,这样就能大大的减少与dom的交互次数,提高性能。
缺点:
但使用不当会造成事件在不应该触发时触发
如下面的例子所示。
var list = document.getElementById("myLinks");
list.onclick = function(event){
//target代表真正触发点击的元素
console.log(event.target);
var target = event.target;
switch(target.id){
case "doSomething":
document.title = "I changed the document's title";
break;
case "goSomewhere":
location.href = "http://www.wrox.com";
break;
case "sayHi":
alert("hi");
break;
}
};
模拟事件
createEvent()方法
使用 createEvent()方法创建 event ,传递一个代表类型的字符串参数
- UIEvents:一般化的 UI 事件。鼠标事件和键盘事件都继承自 UI 事件。DOM3 级中是 UIEvent。
- MouseEvents:一般化的鼠标事件。DOM3 级中是 MouseEvent。
- MutationEvents:一般化的 DOM 变动事件。DOM3 级中是 MutationEvent。
- HTMLEvents:一般化的 HTML 事件。没有对应的 DOM3 级事件(HTML 事件被分散到其他类别中)。
鼠标模拟事件
var btn = document.getElementById("myBtn");
//指定鼠标事件方法
btn.onclick = function(){
alert('12345');
}
//创建事件对象
var event = document.createEvent("MouseEvents");
//初始化事件对象,15个参数
event.initMouseEvent("click", true, true, document.defaultView, 0, 0, 0, 0, 0,
false, false, false, false, 0, null);
//触发事件
btn.dispatchEvent(event);
模拟键盘事件
IE9 是目前唯一支持 DOM3 级键盘事件的浏览器,火狐用自己的方式支持。
只能利用这种技术来模拟 keydown 和 keyup 事件。
var textbox = document.getElementById("myTextbox"),event;
//以 DOM3 级方式创建事件对象
if (document.implementation.hasFeature("KeyboardEvents", "3.0")){
event = document.createEvent("KeyboardEvent");
//初始化事件对象,传入参数
event.initKeyboardEvent("keydown", true, true, document.defaultView, "a",
0, "Shift", 0);
}
//触发事件
textbox.dispatchEvent(event);
模拟变动事件
要模拟变动事件,可以使用 createEvent(“MutationEvents”)创建一个包含initMutationEvent()方法的变动事件对象。
var target = document.getElementById("div1");
var event = document.createEvent("MutationEvents");
// 模拟插入一个Dom
event.initMutationEvent("DOMNodeInserted", true, false, someNode, "","","",0);
target.dispatchEvent(event);
模拟 HTML 事件
同样需要先创建一个 event 对象——通过 createEvent(“HTMLEvents”),
然后再使用这个对象的 initEvent()方法来初始化它即可,如下面的例子所示。
这个例子展示了如何在给定目标上模拟 focus 事件。
var event = document.createEvent("HTMLEvents");
event.initEvent("focus", true, false);
target.dispatchEvent(event);
自定义 DOM 事件
它的目的是让开发人员创建自己的事件。要创建新的自定义事件,可以调用 createEvent(“CustomEvent”)。
返回的对象有一个名为 initCustomEvent()的方法
接收4个参数:
- type(字符串):触发的事件类型,例如"keydown"。
- bubbles(布尔值):表示事件是否应该冒泡。
- cancelable(布尔值):表示事件是否可以取消。
- detail(对象):任意值,保存在 event 对象的 detail 属性中。
var div = document.getElementById("myDiv"),event;
//这里添加的事件名为自定义的事件
div.onmyevent = function(event){
alert("DIV: " + event.detail);
};
//检测是否支持
if (document.implementation.hasFeature("CustomEvents", "3.0")){
//创建自定义事件
event = document.createEvent("CustomEvent");
//传入4个参数
event.initCustomEvent("myevent", true, false, "Hello world!");
//触发事件
div.dispatchEvent(event);
}