1.事件流(事件传播)
概念:
描述页面接收事件的顺序,事件发生时,事件会在元素节点之间按照特定的顺序,依次传播。
思考:
互相嵌套的div,同时给每个元素绑定了不同结果的相同事件,事件会如何传播
IE提出的是冒泡流:
事件开始时由最具体的元素接收,然后逐级向上到DOM顶级节点
网景提出的是捕获流:
事件开始时从DOM顶级节点开始,然后逐层向下传递到最具体的元素
W3C规范:
js事件传播流程主要有三个阶段:
- 事件捕获阶段:从window向 目标 传递的过程
- 处于目标阶段:具体点击的是谁?事件发生在目标身上
- 事件冒泡阶段:从目标向window传递的过程
DOM2可以支持捕获:
事件源 . addEventListener
(‘事件类型’,事件处理函数,布尔true事件捕获、false事件冒泡,不写就是默认冒泡)
DOM0级不支持捕获写法
现代的浏览器在默认情况下,都是事件冒泡模型。
如果想支持事件捕获,需要用DOM2级事件来设置
2.阻止事件冒泡
为什么要阻止
很多情况下我们并不希望事件冒泡的发生。
比如当我们想实现:
- 点击按钮,让元素显示;
- 点击页面空白即(document)时让元素隐藏。
如何组止:
- IE浏览器:
事件对象 . cancelBubble = true
- 非IE浏览器阻止方式为:
事件对象 . stopPropagation()
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="viewport"
content="maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,width=device-width,initial-scale=1.0" />
<style>
div {
width: 200px;
height: 200px;
background-color: pink;
display: none;
}
</style>
</head>
<body>
<button>按钮</button>
<div></div>
</body>
</html>
<script>
var oDiv = document.querySelector('div')
var oBtn = document.querySelector('button')
oBtn.onclick = function (e) {
var ev = e || window.event;
oDiv.style.display = 'block'
ev.stopPropagation();
console.log(ev);
}
document.body.onclick = function () {
oDiv.style.display = 'none'
}
</script>
阻止事件默认行为:
什么是事件默认行为:
没有绑定事件,自身具有的行为就是默认行为
比如:
1.a标签的点击行为
2.form表单的提交行为
3.鼠标右键时弹出菜单的行为
...
如何阻止:
1.IE 低版本:事件对象 . returnValue = false
2.标准浏览器:事件对象 . preventDefault( )
3.在事件代码的最后加 return false (只支持DOM0级事件)
例子:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="viewport"
content="maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,width=device-width,initial-scale=1.0" />
<style>
div {
width: 200px;
height: 200px;
background-color: pink;
display: none;
}
</style>
</head>
<body>
<a href="http://www.baidu.com">百度</a>
<div>
</div>
</body>
</html>
<script>
var oA = document.querySelector('a')
var oDiv = document.querySelector('div')
oA.onclick = function (e) {
var ev = e || window.event;
// ev.preventDefault();//阻止事件默认行为方式
oDiv.style.display = 'block'
return false;//阻止事件默认行为方式2
}
</script>
3.事件委托
出现原因:
- 如果给每个 li 列表项都绑定一个
onclick
,每一个 li 身上都有一个onclick
- 占用系统内存大,资源消耗大
概念:
即是把原本需要绑定在子元素的响应事件(click、keydown…)
事件委托的好处:
- 把绑定事件委托父元素来处理(利用冒泡元素)
- 可以大量节省内存占用,减少事件的绑定
例子:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="viewport"
content="maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,width=device-width,initial-scale=1.0" />
</head>
<body>
<ul>
<li>第1个元素</li>
<li>第2个元素</li>
<li>第3个元素</li>
<li>第4个元素</li>
<li>第5个元素</li>
</ul>
</body>
</html>
<script>
/*
每一个添加点击事件:
1. 先获取所有的li
2. 遍历
3. 给每一个添加点击事件
*/
var oUl = document.querySelector('ul')
oUl.onclick = function(e){
var ev = e || window.event;
// 通过ev.target来获取点击的具体元素
// 点击元素是li的时候,执行获取内容
if (ev.target.nodeName == 'LI') {
console.log(ev.target.innerHTML);
}
}
</script>