说事件绑定得先说事件流
事件流
冒泡型事件流:
事件的传播是从最特定的事件目标到最不特定的事件目标。即从DOM树的叶子到根。【推荐】
捕获型事件流:
事件的传播是从最不特定的事件目标到最特定的事件目标。即从DOM树的根到叶子。
DOM标准采用捕获+冒泡。两种事件流都会触发DOM的所有对象,从document对象开始,也在document对象结束。
来个例子看一下吧!
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="myDiv">Click me!</div>
</body>
</html>
当点击了div时事件流走向
在冒泡型事件流中click事件传播顺序为:
=》 =》 =》document
在捕获型事件流中click事件传播顺序为:
document =》 =》 =》
这里之所以说冒泡,并不是视图上的冒泡,而是结构上的冒泡。这里要弄清楚了,就算在视图上div是独立的,但他的在html结构
结构上依旧是被body所包裹。而冒泡是由内而外向上冒泡。
懂了冒泡之后,捕获就好理解了,就是反向的事件流。由外而内。
事件处理
以上明白了事件流,现在说说怎样处理事件。
HTML事件处理:
直接在标签内绑定事件,例如:<button οnclick=“something()”
这里直接将js内something函数绑定到button上。
缺点:
1.一个方法需要多次引用,而且不符合 行为、结构、样式 相分离的原则。
2.当js的函数名更改,html标签内的方法也需要更改。
DOM 0级事件处理:
在
0级事件处理的较HTML事件处理的有点很明显,他完全写在
缺点:每个DOM元素只能绑定一个同类事件。例如绑定onclick,当你想在绑定onclick会发现他被覆盖了
DOM 2级事件处理(事件监听)
addEventListener(“事件名” , “事件处理函数” , “布尔值”);
false 事件冒泡 true 事件捕获
优点相比前两个就多了。可以选择是事件流。可绑定多个同类事件。事件名可以组成字符串。
到今天的主题了~~
addEventListener() 和 removeEventListener().
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>addEventListener</title>
<script type="text/javascript" src="js/jquery-3.0.0.js"></script>
<style type="text/css">
#content{
width: 100px;
height: 100px;
background: #f9f;
}
</style>
</head>
<body>
<div id="content"></div>
<script type="text/javascript">
//addEventListener 用于向指定元素添加事件句柄
//可以向一个元素添加多次点击事件,后一个点击事件不会覆盖前一个点击事件
var content = document.getElementById("content");
content.addEventListener("click",function(){
console.log("11");
},false)
content.addEventListener("click",function(){
console.log("22");
},false)
content.addEventListener("mouseenter",add,false);
function add(){
console.log("333");
}
content.removeEventListener("mouseenter",add,false);
</script>
</body>
</html>
注意:removeEventListener()
不能移除匿名函数,像上面add()这种是可以的。removeEventListener需要知道你需要移出的是哪个事件处理函数。匿名函数丢弃了自身函数名,所以移出不了。
下面再讲一些补充吧。
阻止默认事件preventDefault()
document.body.addEventListener('touchmove', function (event) {
event.preventDefault();
},false);
阻止事件冒泡stopPropagation()
解释:只点击了button,但是包含button的div也执行了,这属于事件冒泡,事件逐级向上传递,传给了div,有时并不需要事件冒泡,可以通过stopPropagation()
<div id="div">
<button id="btn">按钮</button>
</div>
<script>
document.getElementById("btn").addEventListener("click",showType);
document.getElementById("div").addEventListener("click",showDiv);
function showType(event){
alert(event.type);
event.stopPropagation();
}
function showDiv(){
alert("div");
}
</script>
事件代理
这里归类可能没归好,也看看吧
传统的事件处理中,需要为每个元素添加事件处理器。js事件代理则是一种简单有效的技巧,通过它可以把事件处理器添加到一个父级元素上,从而避免把事件处理器添加到多个子级元素上。
事件代理的原理用到的就是事件冒泡和目标元素,把事件处理器添加到父元素,等待子元素事件冒泡,并且父元素能够通过target(IE为srcElement)判断是哪个子元素,从而做相应处理
传统事件处理,为每个元素添加事件处理器,代码如下:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<ul id="color-list">
<li>red</li>
<li>orange</li>
<li>yellow</li>
<li>green</li>
<li>blue</li>
<li>indigo</li>
<li>purple</li>
</ul>
<script>
(function(){
var colorList=document.getElementById("color-list");
var colors=colorList.getElementsByTagName("li");
for(var i=0;i<colors.length;i++)
{
colors[i].addEventListener('click',showColor,false);
};
function showColor(e)
{
e=e||window.event;
var targetElement=e.target||e.srcElement;
alert(targetElement.innerHTML);
}
})();
</script>
</body>
</html>
事件代理的处理方式,代码如下:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<ul id="color-list">
<li>red</li>
<li>orange</li>
<li>yellow</li>
<li>green</li>
<li>blue</li>
<li>indigo</li>
<li>purple</li>
</ul>
<script>
(function(){
var colorList=document.getElementById("color-list");
colorList.addEventListener('click',showColor,false);
function showColor (e) {
e=e||window.event;
var targetElement=e.target||e.srcElement;
if(targetElement.nodeName.toLowerCase()==="li"){
alert(targetElement.innerHTML);
}
}
})();
</script>
</body>
</html>
###事件代理的好处
总结一下事件代理的好处:
将多个事件处理器减少到一个,因为事件处理器要驻留内存,这样就提高了性能。想象如果有一个100行的表格,对比传统的为每个单元格绑定事件处理器的方式和事件代理(即table上添加一个事件处理器),不难得出结论,事件代理确实避免了一些潜在的风险,提高了性能。
DOM更新无需重新绑定事件处理器,因为事件代理对不同子元素可采用不同处理方法。如果新增其他子元素(a,span,div等),直接修改事件代理的事件处理函数即可,不需要重新绑定处理器,不需要再次循环遍历。
而代理事件需要注意的是事件冒泡, 例如:Li里有span,这时我只想操作Li那我就要用到阻止冒泡了。
好了,就到这里吧。本次分享到这里就结束了,作者自身的技术不是很好,如果有哪里误导了大家,请留言提醒我一下。
如果还有疑问请参考【JavaScript 事件参考手册】