绑定事件的监听函数 (事件处理函数)
(1)HTML 的 on- 属性
<body onload="doSomething()">
<div onclick="console.log('触发事件')">
元素的事件监听属性,都是on加上事件名,比如click就是on + click
,表示click事件的监听代码。
注意,这些属性的值是将会执行的代码,而不是一个函数。
(2)元素节点的事件属性
function doSomething(){
console.log('页面加载完毕');
}
window.onload = doSomething;
// <div class="myDiv" >mydiv</div>
var div = document.getElementsByClassName('myDiv')[0];
div.onclick = function(){
console.log('触发点击事件');
}
元素节点的事件属性,也都是on加上事件名,比如click就是on + click
,表示click事件的监听函数。
不同的是,它的值是函数名
同一个事件只能绑定一个监听函数,也就是说,如果定义两次onclick属性,后一次定义会覆盖前一次
解除绑定,可以 div.onclick = null
如:
// <div class="myDiv" >mydiv</div>
var div = document.getElementsByClassName('myDiv')[0];
div.onclick = function(){
console.log('触发点击事件');
this.onclick = null; // 点击一次后就被取消
}
(3)addEventListener()
function doSomething(){
console.log('页面加载完毕');
}
window.addEventListener('load', doSomething, false);
// <div class="myDiv" >mydiv</div>
var div = document.getElementsByClassName('myDiv')[0];
div.addEventListener('click',function(){
console.log('触发点击事件');
},false);
一个对象的同一个事件可以添加多个监听函数
addEventListener()
兼容性:IE 9 以下的IE浏览器不兼容
addEventListener()
的三个参数分别为
- 事件名称
- 监听函数
- 布尔值,
true
表示监听函数在捕获阶段触发,false
表示监听函数在冒泡阶段触发,默认为false。该参数可选。
解除绑定,removeEventListener(type, fn, false);
解绑时,事件和监听函数要对应。如果绑定匿名函数,则无法解除绑定。
(4)attachEvent()
IE独有的函数
attachEvent( 'on'+ 事件名称 , 监听函数 )
// <div class="myDiv" >mydiv</div>
var div = document.getElementsByClassName('myDiv')[0];
div.attachEvent('onclick', function(){
console.log('触发点击事件');
})
一个对象的同一个事件可以添加多个监听函数
解除绑定,detachEvent('on' + type, fn);
解绑时,事件和监听函数要对应。如果绑定匿名函数,则无法解除绑定。
this 的指向
以上四个 绑定事件的监听函数的方法中,
除了attachEvent()
中的监听函数内部的this
指向window
其余三个,监听函数内部的this
指向触发事件的那个元素节点本身。
封装一个有兼容性的,绑定事件的监听函数的方法
function addEvent(elem, type, handle){
if (elem.addEventListener) {
elem.addEventListener(type, handle, false);
}else if(elem.attachEvent){
elem.attachEvent('on' + type, function(){
handle.call(elem); //为了 handle 函数里面的 this 指向触发事件的那个元素节点本身
});
}else{
elem['on' + type] = handle;
}
}
关于绑定事件处理函数出现的闭包
一但绑定事件的处理函数出现在了循环里面,就要注意是否形成闭包。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<script type="text/javascript">
var liCol = document.getElementsByTagName('li'),
len = liCol.length;
for (var i = 0; i < len; i++) {
(function(i){ // 立执行函数
liCol[i].addEventListener('click',function(){
console.log(i);
//console.log(this.innerHTML);
})
}(i))
}
</script>
</body>
</html>
事件对象
事件发生以后,会产生一个事件对象,作为参数传给监听函数。(IE不会把事件对象传到监听函数里面,会传到window.event
)
事件对象里包含了当前事件发生时的状态和信息。
事件对象的一些属性
事件源对象:
event.target
火狐使用这个表示
event.srcElement
IE 使用这个表示
chrome浏览器两者都有
//<div class="myDiv" ><p>点击</p></div>
var div = document.getElementsByTagName('div')[0];
var p = document.getElementsByTagName('p')[0];
div.onclick = function(e){
var event = e || window.event; // 兼容性写法,
//或 || 从左到右执行判断两边的表达式,如左边表达式为ture,则直接返回左边表达式的值,不再执行右边表达式进行判断;
console.log(event);
var target = event.target || event.srcElement; // 兼容性写法,
console.log(target); // <p>点击</p>
}
事件的传递
一个事件发生后,会在子元素和父元素之间传播。
触发顺序:先捕获,后冒泡
IE没有捕获阶段
捕获阶段:从window
对象传导到目标节点(从父元素传递到子元素)
冒泡阶段:从目标节点传导回window
对象(从子元素传递到父元素)
focus,blur,change,submit,reset,select等事件不冒泡。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div>
<p>点击</p>
</div>
<script>
var div = document.getElementsByTagName('div')[0],
p = document.getElementsByTagName('p')[0];
function test(){
console.log(this.tagName);
}
div.addEventListener('click', test, true);
p.addEventListener('click', test, true);
div.addEventListener('click', test, false);
p.addEventListener('click', test, false);
</script>
</body>
</html>
// DIV P P DIV
上例,<p>点击</p>
被点击。事件传播顺序,在捕获阶段依次为window、document、html、body、div、p
,在冒泡阶段依次为p、div、body、html、document、window
。
取消冒泡
(1)W3C标准 event.stopPropagation();
(兼容性:IE9 以下版本不支持)
(2)IE 可使用 event.cancelBubble = true;
如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div>
<p>点击</p>
</div>
<script>
var div = document.getElementsByTagName('div')[0],
p = document.getElementsByTagName('p')[0];
function test(event){
event.stopPropagation(); // 取消冒泡
//event.cancelBubble = true;
console.log(this.tagName);
}
div.onclick = test;
p.onclick = test;
</script>
</body>
</html>
// p
封装取消冒泡函数
function stopBubble(event){
if(event.stopPropagation){
event.stopPropagation();
}else{
event.cancelBubble = true;
}
}
阻止默认事件
默认事件,如表单提交,a标签跳转,右键菜单等
(1)return false;
(绑定事件的监听函数 使用第(1)、(2)种方法时,才有效。)
(2)W3C标准 event.preventDefault();
(兼容性:IE9 以下版本不支持)
(3)IE 可使用 event.returnValue = false;
封装阻止默认事件函数
function cancelHandler(event){
if (event.preventDefault) {
event.preventDefault();
}else{
event.returnValue = false;
}
}
<a>
标签拿来当按钮用时,取消<a>
标签的默认事件,还可以在href
中使用协议限定符javascript:
<a href="" onclick="doSomething();return false">baidu.com</a>
<!-- 或 -->
<a href="javascript:void(0)" onclick="doSomething()">baidu.com</a>
事件的代理(委托)
利用了事件冒泡
和事件源对象
进行处理。
由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理(delegation)。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<script>
var ul = document.getElementsByTagName('ul')[0];
ul.onclick = function(e){
var event = e || window.event; // 兼容性写法
var target = event.target || event.srcElement; // 兼容性写法
console.log(target.innerHTML);
}
</script>
</body>
</html>
鼠标事件
mousedown
:按下鼠标键时触发。
mouseup
:释放按下的鼠标键时触发。
click
:点击鼠标时触发。指的是,用户在同一个位置先完成mousedown动作,再完成mouseup动作。
因此,触发顺序是,mousedown首先触发,mouseup接着触发,click最后触发。
mousemove
:当鼠标在一个节点内部移动时触发。
mouseenter
:鼠标进入一个节点时触发。
mouseleave
:鼠标离开一个节点时触发。
mouseover
:鼠标进入一个节点时触发。
mouseout
:鼠标离开一个节点时触发。
mouseover事件和mouseenter事件,都是鼠标进入一个节点时触发。两者的区别是,mouseenter事件只触发一次,而只要鼠标在节点内部移动,mouseover事件会在子节点上触发多次。
mouseout事件和mouseleave事件,都是鼠标离开一个节点时触发。两者的区别是,在父元素内部离开一个子元素时,mouseleave事件不会触发,而mouseout事件会触发。
contextmenu
:按下鼠标右键时(上下文菜单出现前)触发。
鼠标事件对象的event.button
属性来区分鼠标的按键,0
表示左键,1
表示中间,2
表示右键。
DOM3标准规定:click
事件只能监听鼠标左键,只能通过mousedown和mouseup来判断鼠标键
拖拽的例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div style="width: 100px; height: 100px; background-color: red; position: absolute; left:0;top: 0;"></div>
<script>
var div = document.getElementsByTagName('div')[0];
function drag(elem){
elem.onmousedown = function(e){
var event = e || window.event;
// console.log(' 点 ');
var disX = event.offsetX,
disY = event.offsetY;
document.onmousemove = function(e){
var event = e || window.event;
div.style.left = e.pageX - disX + 'px';
div.style.top = e.pageY - disY + 'px';
}
elem.onmouseup = function(){
// console.log(' 松 ');
document.onmousemove = null;
}
}
}
drag(div);
</script>
</body>
</html>
键盘事件
(略)
文本操作事件
input
事件
当<input>
、<select>
、<textarea>
的值发生变化时触发。对于复选框(<input type=checkbox>
)或单选框(<input type=radio>
),用户改变选项时,也会触发这个事件。
var input = document.getElementsByTagName('input')[0];
input.oninput = function(){
console.log(this.value);
}
change
事件
change在元素失去焦点时发生,如果值发生了变化,则触发。
focus
事件,元素获得焦点
blur
事件,元素失去焦点
// <input type="text" value="请输入关键字" style="color: #999;">
var input = document.getElementsByTagName('input')[0];
input.onfocus = function(){
if (this.value == '请输入关键字') {this.value = '';}
this.style.color = '#424242';
}
input.onblur = function(){
if(this.value == ''){this.value = '请输入关键字';}
this.style.color = '#999';
}
窗体操作类事件(window上的事件)
scroll
事件,当滚动条滚动时触发。
load
事件,在页面或某个资源加载成功时触发。
window.onload = function(){ }
整个页面资源加载完后触发。一般不用