一、基本概念
0x1 事件
1、定义
事件是可以被 JavaScript 侦测到的行为,通俗的讲就是当用户与Web页面进行某些交互时,解释器就会创建响应的event对象以描述事件信息。
2、事件句柄
事件句柄(又称事件处理函数、事件监听函数),指用于响应某个事件而调用的函数。每一个事件均对应一个事件句柄,在程序执行时,将相应的函数或语句指定给事件句柄,则在该事件发生时,浏览器便执行指定的函数或语句。
0x2 事件定义
一个事件的定义必须有三部:
- 事件对象
- 为事件对象绑定一个事件类型
- 事件句柄
为特定事件定义监听函数有三种方式:
(1)、直接在HTML中定义元素的事件相关属性
缺点:违反了“ 内容与行为相分离” 的原则,应尽可能少用。
<button onclick="alert('hello')">按钮</button>
<body onload="init()">...</body>
(2)、 DOM0级事件
在JavaScript中为元素的事件相关属性赋值:
缺点:此语法实现了“ 内容与行为相分离” ,但元素只能绑定一个监听函数。
<button id="myBtn">点击我</button>
<script type="text/javascript">
var btn = document.getElementById("myBtn");
btn.onclick = function () {
alert('Clicked');
}
var btn = document.getElementById("myBtn");
btn.onclick = function () {
alert(this.id);
}
</script>
(3)、 DOM2级事件
高级事件处理方式,一个事件可以绑定多个监听函数
此语法可以为一个元素绑定多个监听函数,但需要注意浏览器兼容性问题
DOM2支持同一dom元素注册多个同种事件。
DOM2新增了捕获和冒泡的概念。
btn.addEventListener("click",function(){},false); // DOM
btn.attachEvent("onclick",function(){}); // IE
document.body.addEventListener("load",init);
document.body.attachEvent("onload",init);
function init(){ //... }
Demo
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function () {
alert(this.id);
}, false);
0x3 DOM事件流
1、添加移除事件
- addEventListener()
- removeEventListener()
element.addEventListener(event, function, useCapture)
event : 必须。字符串,指定事件名。
function:必须。指定要事件触发时执行的函数。
useCapture:可选。布尔值,指定事件是否在捕获或冒泡阶段执行
//要想移除事件成功必须要保证addEventListener和removeEventListener里面的所有参数一致,匿名函数一般不可以
2、IE事件流
- attachEvent()
- detachEvent()
语法:element.attachEvent(event, function)
功能:用于向指定元素添加事件句柄
event : 必须。字符串,指定事件名,必须加“on” 前缀。
function:必须。指定要事件触发时执行的函数。
事件绑定与移除的兼容性代码
var EventUtil = {
addHandler: function (element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = null
}
},
removeHandler: function (element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null
}
}
}
var btn = document.getElementById("myBtn");
var handler = function () {
alert("Clicked");
}
EventUtil.addHandler(btn, "click", handler);
EventUtil.removeHandler(btn, "click", handler);
3、事件周期
解释器创建一个event对象后,会按如下过程将其在HTML元素间进行传播
- 第一阶段:事件捕获,事件对象沿DOM树向下传播
- 第二阶段:目标触发,运行事件监听函数
- 第三阶段:事件冒泡,事件沿DOM树向上传播
事件的冒泡处理机制
<div id="parent">
<div id="child" class="child"></div>
</div>
<ul>
<li>item1</li>
<li>item2</li>
<li>item3</li>
<li>item4</li>
<li>item5</li>
<li>item6</li>
</ul>
<script type="text/javascript">
// 事件冒泡
document.getElementById("parent").addEventListener("click", function (e) {
alert("parent事件被触发," + this.id);
})
document.getElementById("child").addEventListener("click", function (e) {
alert("child事件被触发," + this.id)
})
// 事件捕获
document.getElementById("parent").addEventListener("click", function (e) {
alert("parent事件被触发," + e.target.id);
}, true)
document.getElementById("child").addEventListener("click", function (e) {
alert("child事件被触发," + e.target.id)
}, true)
// 看个小案例
// 这个是利用事件冒泡
$("ul").on("mouseover", function (e) {
$(e.target).css("background-color", "#ddd").siblings().css("background-color", "white");
})
// 不利用事件捕获,貌似没有任何区别
$("li").on("mouseover", function () {
$(this).css("background-color", "#ddd").siblings().css("background-color", "white");
})
// 但是$("li")已经遍历了li,还有就是如果我们要插入一个新的li,那么还要给li重新添加事件,性能太差
$("li").on("mouseover", function () {
$(this).css("background-color", "#ddd").siblings().css("background-color", "white");
})
// 如果插入一个li
$("ul").on("mouseover", function () {
$("<li>item7</li>").appendTo("ul"); // item7直接具有事件,无需重新绑定事件
})
$("li").on("mouseover", function () {
$("<li>item7</li>").appendTo("ul"); // item7是不具有事件的,需要重新绑定事件
})
</script>
4、Event对象
- type:事件的类型;
- srcElement/target:事件源,就是发生事件的元素;
- cancelBubble:布尔属性,设为true的时候,将停止事件进一步起泡到包容层次的元素;(e.cancelBubble = true; 相当e.stopPropagation(););
- returnValue:布尔属性,设置为false的时候可以组织浏览器执行默认
的事件动作;(e.returnValue = false; 相当于 e.preventDefault(););
<button id="myBtn">点击我</button>
<script type="text/javascript">
// 都含有event事件
var btn = document.getElementById("myBtn");
btn.onclick = function (event) {
alert(event.type);
}
btn.addEventListener = function (event) {
alert(event.type);
}
// target和currentTarget
var btn = document.getElementById("myBtn");
btn.onclick = function (event) {
alert(event.currentTarget === this); //true
alert(event.target === this); //true
}
document.body.onclick = function (event) {
alert(event.currentTarget === document.body); //true
alert(this === document.body); //true
alert(event.target === document.getElementById("myBtn")); //true
}
// type的作用
var btn = document.getElementById("myBtn");
var handler = function (event) {
switch (event.type) {
case "click":
alert("Clicked");
break;
case "mouseover":
event.target.style.backgroundColor = "red";
break;
case "mouseout":
event.target.style.backgroundColor = "";
break;
}
};
btn.onclick = handler;
btn.onmouseover = handler;
btn.onmouseout = handler;
// 阻止默认行为
var link = document.getElementById("myLink");
link.onclick = function (event) {
event.preventDefault();
}
// 取消事件捕获或者冒泡
var btn = document.getElementById("myBtn");
btn.onclick = function (event) {
alert("Clicked");
event.stopPropagation();
}
document.body.onclick = function (event) {
alert("Body clicked");
}
// eventPhase
var btn = document.getElementById("myBtn");
btn.onclick = function (event) {
alert(event.eventPhase); //2 事件处理程序处于目标对象上
}
document.body.addEventListener("click", function (event) {
alert(event.eventPhase); //1 捕获阶段调用的事件处理程序
}, true);
document.body.onclick = function (event) {
alert(event.eventPhase); //3 冒泡阶段调用的事件处理程序
}
</script>