事件代理(委托)

小段拜读几篇关于事件委托的文章以后,学习了其中的姿势(咳咳,知识。。。),于是写下这篇随笔。还是和上篇文章一样的提醒,本随笔用于小段学习的知识总结,如果你看了这篇随笔发现错误,还请指出(我怕误人子弟)-

事件委托在JavaScript高级程序设计中定义为:利用事件冒泡,只指定一个事件处理程序,来处理一类型的所有事件。

就我理解的是:利用事件冒泡的机制,所有子节点中发生了某一类的事件以后,都会冒泡到父级,所以委托父节点来代为处理这一类事件。

现在有这么一个要求那就是,有一个ul标签中有一些li,当鼠标滑入某个li标签,相应的li标签背景变红,鼠标移出,恢复原来样式。

列表代码如下:

<ul id="parent">
	<li class="child">child_1</li>
	<li class="child">child_2</li>
	<li class="child">child_3</li>
	<li class="child">child_4</li>
</ul>

记得在学得事件委托之前,我就会写出逻辑和下面的js一样的代码:

function addEvent() {
	var aChild = document.getElementsByClassName('child');
	
	// 通过遍历所有的class为child的li元素绑定事件
	for(var i = 0; i < aChild.length; i++) {
		aChild[i].onmouseover = function() {
			this.style.background = "orange";
		};

		aChild[i].onmouseout = function() {
			this.style.background = '';
		};
	}
}

addEvent();

那样不就实现了想要的效果了吗?实际上确实是这样。那如果我们现在的增加点要求,我们可以随意的在ul中增加li标签,并且鼠标移入移出li标签的效果和前面的一样。我当时就在想,wocao这个也太简单了吧,于是噼里啪啦就写出下面的代码出来。

var parent = document.getElementById('parent');

function addEvent() {
	var aChild = document.getElementsByClassName('child');
	
	// 通过遍历所有的class为child的li元素绑定事件
	for(var i = 0; i < aChild.length; i++) {
		aChild[i].onmouseover = function() {
			this.style.background = "orange";
		};

		aChild[i].onmouseout = function() {
			this.style.background = '';
		};
	}
}

addEvent();

var newChild = document.createElement('li');
newChild.className = 'child';
newChild.innerText = 'child_5';
parent.appendChild(newChild);

/* 
 * 在这里再次调用addEvent原因是,
 * 前面调用addEvent的时候并没有内容为child_5的节点,
 * 所以只有前4个li拥有鼠标移入移出的事件监听函数。
 * 后面再次调用addEvent,
 * 此时内容child_5的li已经存在dom树中,
 * 所以现在所有的li都有了鼠标移入移出的事件监听函数了。
 */
addEvent();

上面的代码效果是实现了,但是我们每次添加li节点以后都要对每一个li节点进行操作,这样是十分消耗内存,要知道系统分配给浏览器的内存是有限的。

下面将展示事件代理的代码:

var parent = document.getElementById('parent');
parent.addEventListener('mouseover', function(ev) {
  	/* 
  	 * 利用事件对象ev中的target属性可以获取到发生事件的节点,
  	 * 再调用节点对象的nodeName属性获取到标签名,
  	 * 注意此时获取到的标签名是大写字母,
  	 * 调用字符串的toLowerCase()方法就可以将字符串中的字母全变成小写
  	 */
  	if(ev.target.nodeName.toLowerCase() === 'li') {
  		ev.target.style.background = 'orange';
  	}	
});

// 鼠标移出和鼠标移入一样的处理方式
parent.addEventListener('mouseout', function(ev) {
  	if(ev.target.nodeName.toLowerCase() === 'li') {
  		ev.target.style.background = '';
  	}
});

上面的代码中我们给id为parent的ul添加事件监听,在li节点中不管鼠标移入或者移出,由于事件冒泡机制,都会被ul监听到。通过父节点的事件对象ev的target属性(ev.target)即时获取到发生事件的子节点。

接下来我们试下父节点的监听事件是否可以监听到新增的li节点。

var parent = document.getElementById('parent');
parent.addEventListener('mouseover', function(ev) {
  	/* 
  	 * 利用事件对象ev中的target属性可以获取到发生事件的节点,
  	 * 再调用节点对象的nodeName属性获取到标签名,
  	 * 注意此时获取到的标签名是大写字母,
  	 * 调用字符串的toLowerCase()方法就可以将字符串中的字母全变成小写
  	 */
  	if(ev.target.nodeName.toLowerCase() === 'li') {
  		ev.target.style.background = 'orange';
  	}	
});

// 鼠标移出和鼠标移入一样的处理方式
parent.addEventListener('mouseout', function(ev) {
  	if(ev.target.nodeName.toLowerCase() === 'li') {
  		ev.target.style.background = '';
  	}
});

var newChild = document.createElement('li');
newChild.className = 'child';
newChild.innerText = 'child_5';
parent.appendChild(newChild);

image
从效果图我们可以看到,当鼠标滑入新增的child_5时,它的背景也变成了橘色。

小段讲得有点粗糙有什么疑惑,请留言通知我。

posted @ 2018-03-18 00:44  duan777  阅读(137)  评论(0编辑  收藏  举报