JavaScript-DOM-事件委派
前有周先生“人生的三次觉醒”,后有我对问题的四次思考。这次我通过对一个小功能的不断思考与完善一步步的了解了究竟什么是事件委派?
例子描述:
有一个列表其中有几个初始列表项,还有一个新增按钮。通过每点击一次新增按钮就可以新增一个列表项。还要为每个列表项添加点击弹出对话框事件,这时我们该如何去做?
我的第一次思考
那我先想到的就是通过循环遍历列表元素来逐个添加!哈哈哈,有没有想法一致的呢?如果一致那就试一下咯!如果没有就直接跳到下一段。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>想法一</title>
<script>
window.onload = function () {
// 新增列表项
let btn = document.getElementsByTagName('button').item(0);
let ul = document.getElementsByTagName('ul')[0];
btn.onclick = function () {
let liitem = document.createElement('li');
liitem.innerHTML = '新增列表项';
ul.appendChild(liitem);
}
let lis = document.getElementsByTagName('li');
// 循环遍历添加点击事件
for (i = 0; i < lis.length; i++) {
lis[i].onclick = function () {
alert('点我干嘛?');
}
}
}
</script>
<style>
li:hover {
background-color: yellowgreen;
}
</style>
</head>
<body>
<ul>
<p>一段文字</p>
<li>列表二</li>
<li>列表三</li>
<li>列表四</li>
</ul>
<button>新增</button>
</body>
</html>
运行后发现原有列表项点击都可以弹出对话框,但是按钮新增的并不可以。那是因为循环添加点击事件已经在一开始就解析加载完了,而添加新的列表项时不会再重新执行循环???那不行啊!
我的第二次思考
所以为了解决上面的问题我又想到,哎呀,不是之前学过循环器。不能自己动?那我帮他动嘛!所以我果断添加了一个循环器,代码如下:
// 循环遍历添加点击事件
let cr = function(){
for (i = 0; i < lis.length; i++) {
lis[i].onclick = function () {
alert('点我干嘛?');
}
}
}
// 一秒循环一次
setInterval(cr, 1000);
一试发现咦~可以的呀!但又想到那我要是只添加了两行那他一直执行,这样也太消耗内存,性能太差了!一想我天这不是原子弹打鸟嘛?
我的第三次思考
要是我直接给他的新增函数最后执行一次循环添加函数不就好了。果断试一下:
btn.onclick = function () {
let liitem = document.createElement('li');
liitem.innerHTML = '新增列表项';
ul.appendChild(liitem);
// 新增完后再循环
cr();
}
let lis = document.getElementsByTagName('li');
// 循环遍历添加点击事件
let cr = function(){
for (i = 0; i < lis.length; i++) {
lis[i].onclick = function () {
alert('点我干嘛?');
}
}
}
现在已经比循环器好很多了,但还是感觉美中不足,那这一样的东西还得循环,况且还想给ul里的其他元素添加不同点击效果怎么搞嘞?要是这些事件只添加一次就更好了呀!
我的第四次思考
嗨呀,之前不是还学了事件冒泡嘛!那我把事件统一绑定给元素的共同祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素,从而通过祖先元素响应函数来处理事件。哈哈哈,那这样就完美解决了呀,这不正就是千呼万唤始出来的事件委派!它是利用了冒泡,已经能明显感受到通过委派可以减少事件绑定的次数,提高程序的性能了。还是来运行一下看看咯。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>DOM-事件委派示例</title>
<script>
window.onload = function () {
// 新增列表项
let btn = document.getElementsByTagName('button').item(0);
let ul = document.getElementsByTagName('ul')[0];
btn.onclick = function () {
let liitem = document.createElement('li');
liitem.innerHTML = '新增列表项';
ul.appendChild(liitem);
}
/*
* 事件委派
* -指将事件统一绑定给元素的共同祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素
* 从而通过祖先元素额响应函数来处理事件
* -事件委派是利用了冒泡,通过委派可以减少事件绑定的次数,提高程序的性能
*/
// 为ul绑定一个单击响应函数
ul.onclick = function (event) {
event = event || window.event;
/*
* target
* -表示触发的事件对象, IE部分版本不兼容
* srcElement
* -表示触发的事件对象, IE完全兼容
*/
// 兼容
let target = event.target || event.srcElement;
console.log("触发事件的对象:", target);
if (target.localName == 'li') {
alert('点击了li!');
} else {
alert('点击了其他子元素!');
}
}
}
</script>
<style>
li:hover {
background-color: yellowgreen;
}
</style>
</head>
<body>
<ul>
<p>一段文字</p>
<li>列表二</li>
<li>列表三</li>
<li>列表四</li>
</ul>
<button>新增</button>
</body>
</html>
到这里就结束了,如果有更好方法实现的小伙伴请评论或私信告知呀,互相学习,共同进步!