今天我来实际测试说明一下我所理解的事件代理(事件委托),如有问题欢迎各位指正。
先说说事件代理的概念吧,上面我在事件代理后面加了个括弧,里面又写了个“事件委托”,这里我想先申明一下,这俩名字,说的就是一个意思,之前我一度认为,这是两个东西,其实不是。什么是事件代理?“代理”,顾名思义,就是交给其他人(或物)代办,事件代理就是把事件注册到目标元素的祖先元素上面,再通过实际执行中,判断事件源来确定具体的执行对象。那么,它的作用或者说是带来的好处在哪儿呢?具体又是怎样实现的呢?下面,我们来看看具体的操作。
前段时间我在做公司官网,其中有一个房源列表的部分,需要给列表中的每个元素添加特效,而房源列表的数量是不确定的,即时确定,假如有一百个列表元素,难道我要给其注册100次事件嚒?如果是1000个、2000个房源乃至更多呢?再有,如果是动态添加上去的列表元素,它是得不到事件的,这里就会用到事件代理,我将其简化,用两种方式表现,示例如下:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style type="text/css" rel="stylesheet">
body,ul{
margin: 0px;
padding: 0px;
}
ul{
list-style: none;
width: 100%;
margin: 0 auto;
}
li{
width: 200px;
height: 200px;
border: 1px solid #8c8c8c;
text-align: center;
cursor: pointer;
margin-left: 50px;
display: inline-block;
}
</style>
</head>
<body>
<ul id="newHouse">
<li class="houseNum">泰和公馆</li>
<li class="houseNum">绿地世纪城</li>
<li class="houseNum">罗浮宫</li>
<li class="houseNum">尚景雅筑</li>
</ul>
</body>
<script type="text/javascript">
/*现在我要获取鼠标移上的li的文本,通常这样做*/
var newHouse = document.getElementById('newHouse');
var liArr = document.getElementsByTagName('li');
for(var i=0; i<liArr.length; i++){
liArr[i].onmouseover = function(){
alert(this.innerText);
};
}
</script>
</html>
这样做,有两个问题,其一:如果现在用js动态追加一个li,那么这个li是没有获取文本的事件的,因为事件是循环注册到前面四个li上面的;其二:如果li有成千上万个,一个循环固然可以简单地把事件加上去,但是那就相当于注册了成千上万的EventHandler,那就需要开辟内存来存放这些Hander,这对浏览器来说是个负担,影响性能,现在,我换个方式,html不变,只把js换一下,但是效果依旧,看代码:
<script type="text/javascript">
/*现在我改用事件代理来获取鼠标移上的li的文本*/
var newHouse = document.getElementById('newHouse');
newHouse.onmouseover = function(e){
var e = e || window.event;
var myTarget = e.target || e.srcElement;
//alert(target.innerHTML);
if(myTarget.nodeName.toLowerCase() == "li"){
alert(myTarget.innerText);
}
}
</script>
上述代码亲测有效,解决了第一种方式存在的两个问题,现在再来说说它的原理。对比两个方法的js,我们发现,第一种是将事件绑定到元素自身,而第二种是将事件注册到父级元素上面,通过冒泡机制,从父级来判断哪个元素触发了事件,这里的判断十分巧妙地用到了target这个东西,然后通过target来进行后续的操作,这就是事件代理!
下面,我尝试封装一个事件代理的方法:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style type="text/css" rel="stylesheet">
body{
margin: 0px;
padding: 0px;
}
#newEvent{
width: 200px;
margin: 0 auto;
background-color: #6495ed;
}
p,h3{
text-align: center;
cursor: pointer;
margin: 0px;
border: 1px solid red;
}
#newEvent>div{
width: 100%;
height: 20px;
text-align: center;
cursor: pointer;
}
</style>
</head>
<body>
<div id="newEvent">
<p>hello</p>
<h3>嗨</h3>
<div>小贱</div>
</div>
</body>
<script type="text/javascript">
var newHouse = document.getElementById('newEvent');
EventTarget.prototype.showTxt = function(yourEle, eventType, yourEvent) {
this.addEventListener(eventType, function(e) {
if (e.target.tagName === yourEle.toUpperCase()) {
yourEvent(e);
}
});
};
newHouse.showTxt('p','mouseover',function(e){
alert(e.target.innerText + '我是p标签的文本')
});
newHouse.showTxt('h3','mouseover',function(e){
alert(e.target.innerText + '我属于h3')
});
newHouse.showTxt('div','mouseover',function(e){
alert(e.target.innerText + '我属于div的文本')
});
</script>
</html>
只是一个简单的封装,不喜勿喷,end!