概念
1、事件:点击事件,鼠标移入移出事件等。通常与函数配合,当发生这个事件时,会触发函数。
2、DOM事件流:事件捕获和事件冒泡
DOM模型是一个树型的结构,HTML元素是有层次的。
当HTML上的某个元素产生一个事件时,这个事件就会在DOM树中按照一定的顺序传播,途中所经过的各个节点都会接收到该事件。这个传播的过程就是DOM事件流。
3、DOM事件模型:事件捕获,处于目标阶段,事件冒泡
4、冒泡事件流:
默认情况下,事件使用的是冒泡事件流。当某个元素被触发时,这个事件就会沿着该节点的各个父节点一直冒泡,在各个阶段都可以终止冒泡。如果不在途中停止冒泡,就会一直冒泡到文档的根部。
5、捕获事件流:
和冒泡相反,在捕获事件流中,事件的处理是从根部开始的,事件会从这个元素最祖先的元素一直往下传递。
6、DOM标准事件流模型:
DOM标准事件流同时支持事件冒泡和事件捕获。
先捕获
捕获和冒泡都会触发所有对象,从document开始,再到document结束。
window->document->body->div->button->div->body->document->window
7、事件传导的三个阶段:
1、事件捕获:事件会沿着目标元素的祖先元素向下传递,经过目标节点的每一个祖先节点,一直到目标节点。
看看有没有设置成捕获阶段的,addEventListener(,,true),如果有就先触发了,不用管冒泡(false)的那些
2、处于目标阶段:事件传到到目标元素,浏览器查找到指定给目标元素的监听器,就会执行该监听器。
目标元素触发
3、事件冒泡:事件沿着DOM树向上传送,直到document节点,浏览器会检测监听器(捕获阶段的就不看了)并执行。
看看设置成冒泡的,addEventListener(,, false),一层层向上触发,这时候不用管捕获(true)的那些了
先捕获,捕获到事件源之后通过事件传播进行事件冒泡。
IE10以下不支持捕获,所以就少了这个阶段。
8、两个用于事件绑定的方法
1、addEventListener(event, listener, useCapture)
event:事件名称,比如click,没有on
listener:监听函数
useCapture:是否使用事件捕获进行事件捕捉,默认false,默认用的是事件冒泡
2、attachEvent(event, listener),主要用于IE10以下的
event:事件名称,比如onclick
listener:监听函数
9、阻止
1、阻止事件冒泡:event.stopPropagation()
2、阻止默认事件:event.preventDefault()
10、事件委托:一个事件本来要绑定到某个元素上,但是给它绑定到了父元素(祖先元素)上,利用事件冒泡原理,触发执行
事件委托在jQuery中的表现: $(document).on("click", function(){})这种的。一般用于动态生成的元素。
11、事件委托的例子
1、通过parent元素给children元素注册click事件
2、新添加的元素也有事件
3、获取点击元素的下标
12、事件委托的好处
1、提高网页性能
本来要对所有li都添加点击事件,现在只需要给Ul添加一个点击事件。减少了DOM操作。
2、通过事件委托添加的事件,对于后来添加上的元素同样有效
如何解释:比如有个ul,里面有两个li,通过循环给每个li添加点击事件,这两个li都可以触发事件。这时候我们通过append在ul里面再添加两个li,发先也能点击并触发事件。
示例:
var wrapper = document.getElementsByClassName('wrapper')[0];
var content = document.getElementsByClassName('content')[0];
var inner = document.getElementsByClassName('inner')[0];
wrapper.onclick = function(){
console.log("wrapperBubble");
}
content.onclick = function(){
console.log('contentBubble');
}
inner.onclick = function(){
console.log("innerBubble")
}
wrapper.addEventListener('click',function(){
console.log("wrapper");
},true);
content.addEventListener('click',function(){
console.log("content");
},true);
inner.addEventListener('click',function(){
console.log("innerBuhuo");
},true);
先捕获,后冒泡,作用于它自己身上的,就直接先点击哪个是哪个
事件执行的顺序符合谁先绑定谁先执行

并不是所有的事件都冒泡
不冒泡的:focus,blur,change,submit,reset,select等
封装阻止冒泡的方法
function stopBubble(e){
if(e.stopPropagation){
e.stopPropagation();
}else{
e.cancelBubble = true;
}
}
不冒泡的事件:
focus,blur,change,submit,reset,select等
ul里的li不固定,输出li里面的内容,用事件委托的方式
var ul = document.getElementsByTagName('ul')[0];
ul.onclick = function(e){
var e = e || window.event;
var target = e.target || e.srcElement;
e.stopPropagation();
console.log(target.innerText);
}
事件委托的优点:
1、性能高,不需要循环
2、灵活,可以有很多li
综合示例:
<style>
#parent{
width: 200px;
height: 200px;
background-color: red;
}
#child{
width: 100px;
height: 100px;
background-color: green;
}
</style>
<div id="parent">
父元素
<div id="child">子元素</div>
</div>
<ul>
<li>click me</li>
<li>click me</li>
<li>click me</li>
<li>click me</li>
<li>click me</li>
</ul>
// 1、 通过parent元素给children元素注册click事件
var parent = document.getElementById("parent")
var child = document.getElementById("child")
// 我给父元素添加了点击事件,当我点击子元素的时候,同样也能触发
parent.onclick = function(e){
if(e.target.id === "child"){
console.log("click child")
}
}
// 2、对新添加的元素也有事件
var ul = document.querySelector("ul"); // querySelector仅仅返回第一个符合的元素。
var lis = document.getElementsByTagName("li")
ul.onclick = function(e){
var e = e || window.event
var target = e.target || e.srcElement
if(target.nodeName.toLowerCase() === "li"){
console.log("this is li element")
}
}
// 这时候,我们添加几个元素
var li = document.createElement("li")
li.innerHTML = "new click!"
ul.appendChild(li)
// 被添加的元素也有点击事件。
// 3.1、获取点击元素的下标
for(let i=0; i<lis.length; i++){
lis[i].onclick = function(){
console.log(i);
}
}
// 3.2、或者,把i变成li的属性
for(var i=0; i<lis.length; i++){
lis[i].index = i;
lis[i].onclick = function(){
console.log(this.index)
}
}
// 3.3、声明一个立即执行函数
for(var i=0; i< lis.length; i++){
lis[i].onclick = (function(n){
return function(){
console.log(n)
}
})(i)
}
网友评论