首先,这是我自己在学习过程中对于时间冒泡原理的理解,如果有不对的地方,读者尽可提出,不断学习。
一:事件冒泡和阻止冒泡以及使用场景:
1.事件冒泡,就是元素自身的事件被触发后,如果父元素有相同的事件,如onclick事件,那么元素本身的触发状态就会传递,也就是冒到父元素,父元素的相同事件也会一级一级根据嵌套关系向外触发,直到document/window,冒泡过程结束。
2.比如:
<div class="box" styel="width:200px; height: 200px;background_color:'#ddd'">
<div class="box1" styel="width:200px; height: 200px;background_color:'#000'>
<div class="box2" styel="width:200px; height: 200px;background_color:'#eee'></div>
</div>
</div>
<script>
document.querySelector(".box").οnclick=function(){
alert("我是box")
}
document.querySelector(".box1").οnclick=function(){
alert("我是box1")
}
document.querySelector(".box2").οnclick=function(){
alert("我是box2")
}
document.οnclick=function(){
alert("我是document")
}
</script>
此时触发box2中的额onclick事件,会依次弹出“我是box2” 我是box1 我是box1 我是document。这就是事件冒泡。
3.但是事件冒泡在某些应用场景产生一些问题,就是我们不需要触发的事件,由于冒泡的原因,也会运行。所以在这个时候要取消事件冒泡。直接粘图(不知道用什么工具直接粘贴代码,带原格式的。。。)
box.onmouseover = function (event) {
// 阻止冒泡
event = event || window.event;
if(event && event.stopPropagation){
event.stopPropagation();
}else{
event.cancelBubble = true;
}
}
4.那么事件冒泡和组织冒泡什么时候会用到呢?
记着只要是能够触发事件冒泡的情况下,就考虑取消事件冒泡,或者直接利用事件冒泡。
在这里,有一个例子,可以实现阻止事件冒泡来实现,就是模态框的显示和隐藏:(模态框不懂自行参考)。
<div class="mask">
<div class="login" id="login"></div>
</div>
<a href="#">注册</a>
<a href="#">登陆</a>
<script>
//1.给登录绑定事件
var mask = document.getElementsByClassName("mask")[0];
var a = document.getElementsByTagName("a")[1];
a.onclick = function (event) {
//显示模态框
ele.style.display = "block";
//阻止冒泡
event = event || window.event;
if(event && event.stopPropagation){
event.stopPropagation();
}else{
event.cancelBubble = true;
}
}
//2.给document绑定事件,因为可以冒泡,只要判断,点击的不是login,那么隐藏模态框
document.onclick = function (event) {
// 获取点击按钮后传递过来的值。
event = event || window.event;
//兼容获取事件触动时,被传递过来的对象
var aaa = event.target || event.srcElement;
var aaa = event.target?event.target:event.srcElement;
console.log(event.target);
//判断目标值的ID是否等于login,如果等于不隐藏盒子,否则隐藏盒子。
if(aaa.id !== "login"){
mask.style.display = "none";
}
alert("123")
}
</script>
解释:因为document和a都绑定了onclick事件,而且是嵌套的关系,当点击a标签的时候,会造成事件冒泡,既会显示mask模态框,又会弹出“123”的弹出框,所以我们要组织事件的冒泡。如上。
然后判断点击的对象target是不是mask,如果不是mask,就运行mask.style.display="none",模态框消失。
二:事件委托:
1.刚开始接触事件委托概念的时候,很是懵逼,搞不懂到底是一个怎样的委托过程,怎么实现的,但是学到一定程度回过头来,也感觉很好理解。
个人认为事件冒泡存在的意义,就是在事件运行过程中,避免使用循环遍历的方式去给每个同级元素触发相同的事件,而优化性能。要知道,元素量无限大,循环遍历是个噩梦,这也是网站性能优化的一个方面,就是尽量减少使用循环遍历。好了,简单说说我对事件委托理解,实例是摘抄过来的:
如果要实现列表中,当鼠标over的时候,给每个li添加背景:一般想到的方法就是循环遍历添加,如下:
<ul id="ul">
<li>aaaaaaaa</li>
<li>bbbbbbbb</li>
<li>cccccccc</li>
</ul>
window.onload = function(){
var oUl = document.getElementById("ul");
var aLi = oUl.getElementsByTagName("li");
for(var i=0; i<aLi.length; i++){
aLi[i].onmouseover = function(){
this.style.background = "red";
}
aLi[i].onmouseout = function(){
this.style.background = "";
}
}
}
在元素个数不多的情况下可以使用,但元素很多的时候,不建议使用,建议使用冒泡的事件委托:原理如下:
window.onload = function(){
var oUl = document.getElementById("ul");
var aLi = oUl.getElementsByTagName("li");
/*
这里要用到事件源:event 对象,事件源,不管在哪个事件中,只要你操作的那个元素就是事件源。
ie:window.event.srcElement
标准下:event.target
nodeName:找到元素的标签名
*/
oUl.onmouseover = function(ev){
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
//alert(target.innerHTML);
if(target.nodeName.toLowerCase() == "li"){
target.style.background = "red";
}
}
oUl.onmouseout = function(ev){
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
//alert(target.innerHTML);
if(target.nodeName.toLowerCase() == "li"){
target.style.background = "";
}
}
}
只要判断over或者out的对象,nodeName是不是"li",是的话就添加或者去掉背景。
2.还有一种情况:就是新添加的元素:
我们通常会使用Document.createElement("li");创建新的元素,然后再appendChild添加到父标签中。但是有这样一种情况,我是循环遍历给每个li标签绑定了鼠标悬停现实背景色的事件,但这样,新添加的元素就不会被循环到,因为添加之前已经循环停止了:所以:使用事件委托,就很好的解决了这个问题:
window.onload = function(){
var oUl = document.getElementById("ul");
var aLi = oUl.getElementsByTagName("li");
var oBtn = document.getElementById("btn");
var iNow = 4;
oUl.onmouseover = function(ev){
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
//alert(target.innerHTML);
if(target.nodeName.toLowerCase() == "li"){
target.style.background = "red";
}
}
oUl.onmouseout = function(ev){
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
//alert(target.innerHTML);
if(target.nodeName.toLowerCase() == "li"){
target.style.background = "";
}
}
oBtn.onclick = function(){
iNow ++;
var oLi = document.createElement("li");
oLi.innerHTML = 1111 *iNow;
oUl.appendChild(oLi);
}
}