不同的事件类型
load
:Web页面加载完成unload
:Web页面正在卸载(通常是因为请求了一个新页面)error
:浏览器遇到JavaScript错误或有不存在的资源resize
:浏览器窗口的大小发生了变化scroll
:用户使用滚动条移动了页面keydown
:用户第一次按下一个键(按住这个键会反复触发)keyup
:用户松开了一个键keypress
:当用户按下一个键并在屏幕上反映为一个字符时触发。可以通过该事件下的keyCode
属性,该属性返回该字母的ASC2码click
:用户在同一个元素上按下并松开一个按键dblick
:用户在同一个元素上连续二次并松开一个按键mousedown
:用户在一个元素按下鼠标按键mouseup
:用户在一个元素上松开鼠标按键mousemove
:用户移动鼠标(不发生在触屏上)mouseover
:用户将鼠标移到一个元素上(不发生在触屏上)mouseout
:用户将鼠标从一个元素上移开(不发生在触屏上)focus/focusin
:元素得到焦点blur/focusout
:元素失去焦点input
:<input>
或<textarea>
元素中的值发生了变化,或拥有contenteditable
属性的元素中的值发生了变化change
:复选框,单选框或单选按钮的值发生了变化submit
:用户提交表单reset
:用户单击了表单上的重置按钮cut
:用户从一个表单域中剪切了内容copy
:用户从一个表单域中复制了内容paste
:用户用户向表单域中粘贴了内容select
:用户在表单域中选中了一些文本DOMSubtreeModified
:文档发生了变化时触发DOMNodeInserted
:一个节点被插入为另一个节点的直接子节点,如appendChild()
,replaceChild()
,insertBefore()
DOMNodeRemoved
:一个节点从DOM树中被移除时触发DOMNodeInsertedIntoDocument
:一个节点作为后代节点被插入为另一个已经存在于文档中的节点时触发DOMNodeRemovedFromDocument
:一个节点作为后代节点从另一个已经存在于文档中的节点移除时触发。
事件如何触发JavaScript代码
- 选中需要使用脚本进行事件响应的元素节点
- 声明需要在选中节点中响应触发的事件
- 指定当事件发生时需要运行的代码
将事件绑定到元素的三种方法
- HTML事件处理程序(不推荐)
- 传统的DOM事件处理程序
- 第二级DOM监听器
传统的DOM事件处理程序
element(目标DOM元素节点).onevent(绑定到该节点的事件,使用前缀on) = functionName(需要调用的函数的名称(后面不带小括号))
function checkUserName() {
//code
}
var el = document.getElementById('username');
el.onblur = checkUsername;
事件监听器
element.addEventListener('event',functionName[,Boolean(事件流)])
function checkUserName() {
//code
}
var el = document.getElementById('username');
el.addEventListener('blur',checkUsername,false);
在事件处理和事件监听中使用参数
通常,当函数需要一些信息来完成其他工作时,都是通过函数后的小括号传递参数,当解析器看到函数调用后面的小括号时,会直接运行函数中的代码,而在事件处理程序中,需要在事件触发时才运行,因此,就需要把方法调用封装在匿名函数中
el.addEventListener('blur',function(){
check(3);
},false
);
事件流
HTML元素都位于另一些元素中,如果移动鼠标到一个链接上,或者点击一个链接,同样会把鼠标移动到他的父元素上,或者点击它的父元素
如果有一个包含链接的列表项。当将鼠标移到链接上或者点击它时,JavaScript会在<a>
元素上触发事件,同样也会在包含这个<a>
元素的所有元素上触发事件,事件监听器可以绑定到包含<li>
,<ul>
,<body>
,<html>
在内的元素,再加上document对象和window对象。事件发生的顺序被称为事件流。事件流有而两种不同的流向
- 事件冒泡:事件从最具体的节点向外传播到最宽泛的节点。这是事件流的默认类型
- 事件捕获:事件从最宽泛的节点开始向内传播到最具体的节点
使用事件监听器时,addEventListener()
方法的最后一个参数允许选择事件触发的方向,true
表示捕获方式,false
表示冒泡方式
事件对象
每当事件发生时,事件对象中都会包含一些关于该事件的有用信息,事件对象会作为参数传递给任何事件处理程序或事件监听器的函数。如果需要传递一个参数给命名函数,事件对象会作为匿名封装函数的第一个参数传递进去。
target
:事件的目标(srcElement in IE)type
:发生的事件的类型(type in IE)cancelable
:是否可以撤销事件在这个元素的默认行为preventDefault()
:撤销这个事件的默认行为(returnValue in IE)stopPropagation()
:停止继续冒泡或者向下捕获的过程(cancelBubble in IE)
事件委托
为大量的元素创建事件监听器会造成页面速度下降。事件流允许你在父元素上监听事件
如果向DOM树中添加了新的元素,那么就不需要再向这个新元素上添加事件处理程序
<ul id="parent-list">
<li id="post-1">Item 1</li>
<li id="post-2">Item 2</li>
<li id="post-3">Item 3</li>
<li id="post-4">Item 4</li>
<li id="post-5">Item 5</li>
<li id="post-6">Item 6</li>
</ul>
// Get the element, add a click listener...
document.getElementById("parent-list").addEventListener("click", function(e) {
// e.target is the clicked element
// If it was a list item
if(e.target && e.target.nodeName == "LI") {
// List item found
console.log("List item ", e.target.id.replace("post-", ""), " was clicked!");
}
});
//a parent DIV with many children and has a tag with classA class
// Get the parent DIV, add click listener...
document.getElementById("myDiv").addEventListener("click",function(e) {
// e.target was the clicked element
if (e.target && e.target.matches("a.classA")) {
console.log("Anchor element clicked!");
}
});
使用Element.matches API能判断这个元素是否匹配我们想要的元素
jQuery中的事件委托
<ul id="list">
<li><a href="#">item 1</a></li>
<li><a href="#">item 2</a></li>
<li><a href="#">item 3</a></li>
<li><a href="#">item 4</a></li>
</ul>
$("#list").on("click","a",function(e){
e.preventDefault();
console.log($(this).text());
});
使用is()
来进行条件判断
$("#list").on("click","a",function(e){
e.preventDefault();
if($(this).is("[href^='#']")){
$(this).attr("target","_blank");
}
});
polyfill
function getEventTarget(e) {
e = e || window.event;
return e.target || e.srcElement;
}
function selectorMatches(el, selector) {
var p = Element.prototype;
var f = p.matches || p.webkitMatchesSelector || p.mozMatchesSelector || p.msMatchesSelector || function(s) {
return [].indexOf.call(document.querySelectorAll(s), this) !== -1;
};
return f.call(el, selector);
}
优缺点
优点:比之前更少的事件处理和占用更少的内存,不用再DOM更新之后再次附加事件处理 缺点:不是所有的事件都支持冒泡,例如
Example
//Remove item from a list
<ul class="list">
<input type="text" />
<li><em>item 1</em></li>
<li><a href="#">item 2</a></li>
<li><a href="#">item 3</a></li>
<li><a href="#">item 4</a></li>
</ul>
function itemDown(e){
var target,elParent,elGrandparent;
target = e.target;
elParent = target.parentNode;
console.log(e);
console.log(target.parentNode);
elGrandparent = target.parentNode.parentNode;
elGrandparent.removeChild(elParent);
e.preventDefault();
}
var el = document.getElementsByClassName('list')[0];
el.addEventListener('click',function(e){
itemDown(e);
},false);
事件发生的位置
当调用一个函数时,事件对象的target属性是用户获得事件发生在哪个元素上的最好的方法,可以使用this
关键词。当没有参数传递给函数的时候,这种方法是有效的。如果需要向函数传递参数,那么this
关键词将会失效,因为这个函数的所有者不再是事件监听器而是那个匿名函数
focus和blur事件
在表单中更加常用,当用户和表单中独立的元素交互时,向用户显示提示或反馈信息或者需要在用户从一个控件移到下一个控件时,触发表单验证
HTML5事件
DOMContentLoaded
:在DOM树形成后触发(与此同时,图片,css和JavaScript可能还在加载)。在这个事件中,脚本要早于load事件,因为load事件会等待所有资源加载完之后才会触发。这种方式会让页面看起来加载速度更快hashchange
:当URL的hash
值变化时(不会造成整个窗口刷新)触发。hash值通常在链接中用来指定页面中的不同部分。在使用AJAX加载的页面内容中也会被使用。beforeunload
:当页面被卸载之前在window对象上触发,
function setup(){
var textInput;
textInput = document.getElementById('message');
textInput.focus();
}
window.addEventListener('DOMContentLoaded',setup,false);
window.addEventListener('beforeunload',function(event){
return 'Some Message';
});