事件冒泡
1、概念
从实例的元素(事件)向上级父元素一级一级的执行上去,直到到达html
2、代码展示1
<body>
<div id="div1">我是div1
<div id="div2">我是div2
<div id="div3">我是div3
<div id="div4">我是div4</div>
</div>
</div>
</div>
</body>
<script>
let div1 = document.getElementById('div1');
let div2 = document.getElementById('div2');
let div3 = document.getElementById('div3');
let div4 = document.getElementById('div4');
div1.addEventListener('click', function () {
alert('我是div1')
})
div2.addEventListener('click', function () {
alert('我是div2')
})
div3.addEventListener('click', function () {
alert('我是div3')
})
div4.addEventListener('click', function () {
alert('我是div4')
})
</script>
代码分析: 点击div1,弹出div1 点击div2,先弹出div2,然后弹出div1 点击div3,先弹出div3,再弹出div2,在弹出div1 点击div4,先弹出div4,在弹出div3,在弹出div2,在弹出div1 由于存在事件冒泡,所以会执行完自身之后,会执行上一级父元素的事件 addEventListener的第三个参数默认是false,默认是冒泡 addEventListener的第三个参数是true,是捕获
3、代码展示2
<body>
<div id="div1">我是div1
<div id="div2">我是div2
<div id="div3">我是div3
<div id="div4">我是div4</div>
</div>
</div>
</div>
</body>
<script>
let div1 = document.getElementById('div1');
let div2 = document.getElementById('div2');
let div3 = document.getElementById('div3');
let div4 = document.getElementById('div4');
div1.addEventListener('click', function () {
alert('我是div1')
},false)
div2.addEventListener('click', function () {
alert('我是div2')
},true)
div3.addEventListener('click', function () {
alert('我是div3')
},false)
div4.addEventListener('click', function () {
alert('我是div4')
},true)
</script>
代码分析: 点击div1,div1, 点击div2,div2—>div1 点击div3,div2—>div3—>div1 点击div4,div2—>div4—>div3—>div1 当点击事件之前,父级存在捕获,是先执行捕获,在执行冒泡的
4、代码展示3
<body>
<div id="div1">我是div1
<div id="div2">我是div2
<div id="div3">我是div3
<div id="div4">我是div4</div>
</div>
</div>
</div>
</body>
<script>
let div1 = document.getElementById('div1');
let div2 = document.getElementById('div2');
div1.addEventListener('click', function () {
alert('我是div1')
},false)
div2.addEventListener('click', function () {
alert('我是div2捕获')
},true)
div2.addEventListener('click', function () {
alert('我是div2冒泡')
},false)
</script>
代码分析: div2捕获—>div2冒泡—>div1
5、代码展示4
<body>
<div id="div1">我是div1
<div id="div2">我是div2
<div id="div3">我是div3
<div id="div4">我是div4</div>
</div>
</div>
</div>
</body>
<script>
let div1 = document.getElementById('div1');
let div2 = document.getElementById('div2');
div1.addEventListener("click", function () {
alert("div1");
}, false);
div2.addEventListener("click", function () {
alert("div2_冒泡");
}, false);
div2.addEventListener("click", function () {
alert("div2_捕获");
}, true);
</script>
代码分析: div2捕获—>div2冒泡—>div1
6、代码展示5
<body>
<div id="div1" class="div1">
<div id="div2" class="div2"></div>
</div>
</body>
<script>
var div1 = document.getElementById('div1'); //父级
var div2 = document.getElementById('div2');
div2.onclick = function () {
alert(2);
}
div1.onclick = function () {
alert(1);
}
</script>
当我点击div2的时候,弹出了2,然后又弹出了1,所以这里发生了事件冒泡,div2的点击事件传递给了父级div1,div1正好又绑定了事件触发的函数,所以会出现以上的效果 这里有一个比较迷惑的点,可能认为div2的位置在div1里面,点击了div2也就点击了div1,其实通过测试(调整div1和div2的位置是上下布局,发现冒泡还会存在)
7、父级的事件触发函数没有操作
<body>
<div id="div1" class="div1">
<div id="div2" class="div2"></div>
</div>
</body>
<script>
var div1 = document.getElementById('div1'); //父级
var div2 = document.getElementById('div2');
div2.onclick = function () {
alert(2);
}
div1.onclick = function () {
}
</script>
8、需求:点击div1展示div2 ,点击其他地方隐藏div2
<body>
<div id="div1" class="div1">div1</div>
<div id="div2" class="div2">div2</div>
</body>
<script>
var div1 = document.getElementById('div1');
var div2 = document.getElementById('div2');
div1.onclick = function () {
div2.style.display = 'block';
}
document.onclick = function(){
div2.style.display = 'none'
}
</script>
上述的代码并没有按照预期的想法展示,因为发生了事件冒泡,因为div1执行onclick的时候,他会触发父级的点击事件然后一层一层上传,所以document的事件也被触发了,然后执行绑定的事件函数,div2消失了。。所以当点击div1的时候首先,让div2面板显示,只是事件执行太快了,很快又执行了document的点击事件,让面板隐藏。
9、取消事件冒泡
<body>
<div id="div1" class="div1">div1</div>
<div id="div2" class="div2">div2</div>
</body>
<script>
var div1 = document.getElementById('div1');
var div2 = document.getElementById('div2');
div1.onclick = function (ev) {
div2.style.display = 'block';
stopBubble(ev); //停止div1的事件冒泡
}
document.onclick = function () {
div2.style.display = 'none'
}
function stopBubble(e) {
if (e && e.stopPropagation) {
e.stopPropagation(); // w3c标准
} else {
window.event.cancelBubble = true; // IE的方式
}
};
</script>
事件委托
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<ul id="ul">
<li>111111</li>
<li>222222</li>
<li>333333</li>
</ul>
<button id="button">点击</button>
</body>
<script>
window.onload = function () {
let aul = document.getElementById('ul');
let ali = document.getElementsByTagName('li');
let button = document.getElementById('button');
// 3个小li
let num = 3;
// 事件源 :event对象
// ie:window.event.srcElement
// 标准:event.target
aul.onmousemove = function (e) {
let ev = e || window.event;
let target = ev.target || ev.srcElement;
if (target.nodeName.toLowerCase() == 'li') {
target.style.background = 'red';
}
}
aul.onmouseout = function (e) {
let ev = window.event || e;
let target = ev.target || ev.srcElement;
if (target.nodeName.toLowerCase() == 'li') {
target.style.background = ''
}
}
// 实现按钮的监听方法1
// button.addEventListener('click', function () {
// num++;
// let lii = document.createElement('li');
// lii.innerHTML = 111111 * num;
// aul.appendChild(lii);
// })
// 实现按钮的监听方法2
button.onclick = function () {
num++;
let lii = document.createElement('li');
lii.innerHTML = 111111 * num;
aul.appendChild(lii);
}
}
</script>
</html>