一、事件
1. 事件的发生
JavaScript和HTML的交互是通过事件实现的。JavaScript采用异步事件驱动编程模型,当文档、浏览器、元素或与之相关对象发生特定事情时,浏览器会产生事件。如果JavaScript关注特定类型事件,那么它可以注册当这类事件发生时要调用的句柄
- 事件是某个行为或者触发,比如点击、鼠标移动
- 当用户点击鼠标时
- 当网页已加载时
- 当图像已加载时
- 当鼠标移动到元素上时
- 当用户触发按键时
2. 事件的传播机制(原理)
主要有三种模型
-
事件冒泡
事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的元素
-
事件的捕获模型
不太具体的节点更早接收事件,而最具体的元素最后接收事件,和事件冒泡相反
-
DOM事件流
DOM2级事件规定事件流包括三个阶段,事件捕获阶段,处于目标阶段,事件冒泡阶段,首先发生的是事件捕获,为截取事件提供机会,然后是实际目标接收事件,最后是冒泡阶段
Opera、Firefox、Chrome、Safari都支持DOM事件流,IE不支持事件流,只支持事件冒泡
3. 事件的处理程序
我们也称之为事件侦听器(listener),事件就是用户或浏览器自身执行的某种动作。比如click、load、mouseover等,都是事件类型(俗称事件名称),而响应某个事件的方法就叫做事件处理程序或者事件监听器
也就是我们需要提前定义好某些事件发生了该怎么处理,这个过程叫做绑定事件处理程序,了解了这些,我们看看如何给元素添加事件处理程序。
HTML内联方式(不常用,了解)
<input type="button" value="Click Here" onclick="alert('Clicked!');" />
在HTML中指定事件处理程序书写很方便,但是有两个缺点。
存在加载顺序问题,如果事件处理程序在html代码之后加载,用户可能在事件处理程序还未加载完成时就点击按钮之类的触发事件,存在时间差问题
这样书写html代码和JavaScript代码紧密耦合,维护不方便
JavaScript指定事件处理程序(赋值法dom leve1)
通过JavaScript指定事件处理程序就是把一个方法赋值给一个元素的事件处理程序属性。
比如
每个元素都有自己的事件处理程序属性,这些属性名称通常为小写,如onclick等,将这些属性的值设置为一个函数,就可以指定事件处理程序,如下
<input id="btnClick" type="button" value="Click Here" />
<script type="text/javascript">
var btnClick = document.getElementById('btnClick');
btnClick.onclick = function showMessage() {
alert(this.id);
};
</script>
这样处理,事件处理程序被认为是元素的方法,事件处理程序在元素的作用域下运行,this就是当前元素,所以点击button结果是:btnClick
这样还有一个好处,我们可以删除事件处理程序,只需把元素的onclick属性赋为null即可
DOM2事件处理程序(dom level2)
DOM2级事件定义了两个方法用于处理指定和删除事件处理程序的操作:
addEventListener
removeEventListener
所有的DOM节点都包含这两个方法,并且它们都接受三个参数:
事件类型
事件处理方法
布尔参数,如果是true表示在捕获阶段调用事件处理程序,如果是false,则是在
事件冒泡阶段处理
<input id="btnClick" type="button" value="Click Here" />
<script type="text/javascript">
var btnClick = document.getElementById('btnClick');
btnClick.addEventListener('click', function() {
alert(this.id);
}, false);
</script>
上面代码为button添加了click事件的处理程序,在冒泡阶段触发,与上一种方法一样,这个程序也是在元素的作用域下运行,不过有一个好处,我们可以为click事件添加多个处理程序(可以多次赋值不被覆盖。。)
<input id="btnClick" type="button" value="Click Here" />
<script type="text/javascript">
var btnClick = document.getElementById('btnClick');
btnClick.addEventListener('click', function() {
alert(this.id);
}, false);
btnClick.addEventListener('click', function() {
alert('Hello!');
}, false);
</script>
这样两个事件处理程序会在用户点击button后按照添加顺序依次执行。
通过addEventListener添加的事件处理程序只能通过removeEventListener移除,移除时参数与添加的时候相同,这就意味着刚才我们添加的匿名函数无法移除,因为匿名函数虽然方法体一样,但是句柄却不相同,所以当我们有移除事件处理程序的时候可以这样写(不能有匿名函数,必须指定函数名)
<input id="btnClick" type="button" value="Click Here" />
<script type="text/javascript">
var btnClick = document.getElementById('btnClick');
var handler=function() {
alert(this.id);
}
btnClick.addEventListener('click', handler, false);
btnClick.removeEventListener('click', handler, false);
</script>
二、DOM中的事件对象
兼容DOM的浏览器会产生一个event对象传入事件处理程序中。应用一下刚才我们写的addEvent方法
var btnClick = document.getElementById('btnClick');
addEvent(btnClick, 'click', handler);
event对象包含与创建它的特定事件有关的属性和方法,触发事件的类型不同,可用的属性和方法也不同,但是所有事件都会包含
在事件处理程序内部,this始终等同于currentTarget,而target是事件的实际目标。
- 要阻止事件的默认行为,可以使用preventDefault()方法,前提是cancelable值为true,比如我们可以阻止链接导航这一默认行为
document.querySelector('#btn').onclick = function (e) {
e.preventDefault();
}
阻止默认事件,使用preventDefault()
<a href="http://baid.com">baidu</a>
<script>
document.querySelector('a').onclick= function(e){
e.preventDefault()
console.log(this.href)
if(/baidu.com/.test(this.href)){
location.href = this.href
}
}
</script>
<form action="/login">
<input type="text" name="username">
<input type="submit">
</form>
<script>
document.querySelector('form').addEventListener('submit', function(evt){
evt.preventDefault()
if(document.querySelector('input[name=username]').value === 'jirengu'){
this.submit()
}
})
</script>
- stopPropagation()方法可以停止事件在DOM层次的传播,即取消进一步的事件捕获或冒泡。我们可以在button的事件处理程序中调用stopPropagation()从而避免注册在body上的事件发生
var handler = function (e) {
alert(e.type);
e.stopPropagation();
}
addEvent(document.body, 'click', function () { alert('Clicked body')});
var btnClick = document.getElementById('btnClick');
addEvent(btnClick, 'click', handler);
若是注释掉e.stopPropagation(); 在点击button的时候,由于事件冒泡,body的click事件也会触发,但是调用这句后,事件会停止传播
三、事件的特殊处理
事件的传播流程
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<style>
.container,
.box,
.target{
border: 1px solid;
padding: 10px;
}
</style>
<button id="btn">click</button>
<div class="container">
container
<div class="box">
box
<div class="target">target</div>
</div>
</div>
<script>
function $(selector){
return document.querySelector(selector)
}
var btn = $('#btn')
btn.onclick = function (e){
console.log(e)
}
btn.addEventListener('click', function(evt){
console.log(this)
console.log(btn)
console.log(evt.target)
})
$('.container').addEventListener('click', function(e){
console.log('contianer click.. in 捕获阶段')
}, true)
$('.box').addEventListener('click', function(e){
//e.stopPropagation()
console.log('box click.. in 捕获阶段')
}, true)
$('.target').addEventListener('click', function(e){
console.log('target click.. in 捕获阶段')
}, true)
$('.container').addEventListener('click', function(e){
console.log('contianer click.. in 冒泡阶段')
}, false)
$('.box').addEventListener('click', function(e){
//e.stopPropagation()
console.log('box click.. in 冒泡阶段')
}, false)
$('.target').addEventListener('click', function(e){
console.log('target click.. in 冒泡阶段')
}, false)
</script>
</body>
</html>
http://js.jirengu.com/baronerute/1/edit?html,css,js,console