在实际开发中,经常需要为Dom元素绑定事件,如果页面上有4个li元素,点击对应的li,弹出对应的li内容,怎么做呢?是不是很简单?
大多数人的做法都是:获取元素,绑定事件
1 <ul>
2 <li>跟着ghostwu学习javascript设计模式的应用1</li>
3 <li>跟着ghostwu学习javascript设计模式的应用2</li>
4 <li>跟着ghostwu学习javascript设计模式的应用3</li>
5 <li>跟着ghostwu学习javascript设计模式的应用4</li>
6 </ul>
7 <script>
8 var aLi = document.querySelectorAll( "li" );
9 aLi.forEach(( ele, ind ) => {
10 ele.addEventListener( "click", ()=> {
11 alert( ele.innerHTML );
12 } );
13 });
14 </script>
如果页面上有1w个元素, 甚至10w个元素呢?
继续使用上述方式,会有很大的性能问题,这个时候,有人可能要问,实际中的项目 哪有1w个,10w个元素的。一般的项目可能没有,但是社交类的网站,如微博,其他的如大批量文件上传等能功能,都是需要动态创建dom元素,而且数量巨大,并且创建出来的dom元素,一般都需要绑定事件和相应的特效。一般情况下,用普通的绑定事件方式是不能给动态创建的dom元素绑定到事件的,所以这里就产生了两个问题:
1,当页面元素很多的时候,如果给这些元素绑定上事件?
2,当动态创建dom时,如果给动态创建的dom绑定上事件和相应的特效?
这就是本文需要讨论的模式-委托模式
采用事件委托可以顺利解决上面2个问题
那么,什么是事件委托呢?
给元素的父元素绑定事件,利用冒泡原理,当子元素触发事件的时候,会去触发父元素的事件,然后把相应的业务逻辑放在父元素的事件中去处理。通俗点讲就是,子元素不做事件绑定,把绑定事件的操作委托给父元素,这就叫做事件委托, 委托有一个特性,他能够在事件触发中,识别到具体是由哪个子元素触发的,这个就是事件对象的target属性
1 <ul>
2 <li>跟着ghostwu学习javascript设计模式的应用1</li>
3 <li>跟着ghostwu学习javascript设计模式的应用2</li>
4 <li>跟着ghostwu学习javascript设计模式的应用3</li>
5 <li>跟着ghostwu学习javascript设计模式的应用4</li>
6 </ul>
7 <script>
8 var oUl = document.querySelector("ul");
9 oUl.addEventListener( "click", ( ev )=>{
10 var oEvent = ev || event;
11 target = oEvent.target || oEvent.srcElement;
12 alert( target.innerHTML );
13 });
14 </script>
当我们点击li的时候,就能通过事件对象oEvent.target识别到触发事件的li元素, srcElement是兼容ie的写法。
在没有事件委托之间,我们通过javascript做一个hover的功能,一般这么做.
1 <ul>
2 <li>跟着ghostwu学习设计模式</li>
3 <li>跟着ghostwu学习设计模式</li>
4 <li>跟着ghostwu学习设计模式</li>
5 <li>跟着ghostwu学习设计模式</li>
6 <li>跟着ghostwu学习设计模式</li>
7 </ul>
8 <script>
9 var aLi = document.getElementsByTagName( "li" );
10 for( var i = 0, len = aLi.length; i < len; i++ ){
11 aLi[i].onmouseover = function(){
12 this.style.backgroundColor = 'red';
13 }
14 aLi[i].onmouseout = function(){
15 this.style.backgroundColor = '';
16 }
17 }
18 </script>
如果li元素很多,就会产生性能问题,而采用委托模式,我们可以这么做
1 <ul>
2 <li>跟着ghostwu学习设计模式1</li>
3 <li>跟着ghostwu学习设计模式2</li>
4 <li>跟着ghostwu学习设计模式3</li>
5 </ul>
6 <script>
7 var aLi = document.getElementsByTagName("li");
8 var oUl = document.getElementsByTagName( "ul" )[0];
9 oUl.onmouseover = function( ev ){
10 var oEvent = ev || event;
11 var target = oEvent.target || oEvent.srcElement;
12 if ( target.tagName.toLowerCase() == 'li' ) {
13 target.style.backgroundColor = 'red';
14 }
15 }
16 oUl.onmouseout = function( ev ){
17 var oEvent = ev || event;
18 var target = oEvent.target || oEvent.srcElement;
19 if ( target.tagName.toLowerCase() == 'li' ) {
20 target.style.backgroundColor = '';
21 }
22 }
23 </script>
通过事件委托,把元素绑定到父元素,大大提高性能
至此,我们解决了第一个问题:当页面元素很多的时候,如果给这些元素绑定上事件
对于新创建的dom元素,普通绑定事件的方式,是不能绑定到这些dom元素的
1 <input type="button" value="创建">
2 <ul>
3 <li>ghostwu1</li>
4 <li>ghostwu2</li>
5 </ul>
6 <script>
7 var oBtn = document.getElementsByTagName( "input" )[0];
8 var oUl = document.getElementsByTagName( "ul" )[0];
9 var aLi = document.getElementsByTagName( "li" );
10 oBtn.onclick = function(){
11 var oLi = document.createElement( "li" );
12 oLi.innerHTML = 'ghostwu';
13 oUl.appendChild( oLi );
14 }
15 for( var i = 0, len = aLi.length; i < len; i++ ){
16 aLi[i].onmouseover = function(){
17 this.style.backgroundColor = 'red';
18 }
19 aLi[i].onmouseout = function(){
20 this.style.backgroundColor = '';
21 }
22 }
23
24 </script>
新创建的li元素,是不能绑定到onmouseover和onmouseout事件的,我们采用委托模式之后,可以这么做
1 <input type="button" value="创建">
2 <ul>
3 <li>ghostwu1</li>
4 <li>ghostwu2</li>
5 </ul>
6 <script>
7 var oBtn = document.getElementsByTagName("input")[0];
8 var oUl = document.getElementsByTagName("ul")[0];
9 var aLi = document.getElementsByTagName("li");
10 oBtn.onclick = function () {
11 var oLi = document.createElement("li");
12 oLi.innerHTML = 'ghostwu';
13 oUl.appendChild(oLi);
14 }
15 oUl.onmouseover = function( ev ){
16 var oEvent = ev || event;
17 var target = oEvent.target || oEvent.srcElement;
18 if ( target.tagName.toLowerCase() == 'li' ) {
19 target.style.backgroundColor = 'red';
20 }
21 }
22 oUl.onmouseout = function( ev ){
23 var oEvent = ev || event;
24 var target = oEvent.target || oEvent.srcElement;
25 if ( target.tagName.toLowerCase() == 'li' ) {
26 target.style.backgroundColor = '';
27 }
28 }
29 </script>
至此,我们解决了第二个问题:当动态创建dom时,如果给动态创建的dom绑定上事件和相应的特效
最后,我们结合委托模式,来实战一个微博发布的功能,微博发布之后,给动态创建的dom元素添加手风琴折叠功能
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link href="https://cdn.bootcss.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-offset-3 col-md-6">
<form class="form-horizontal">
<div class="form-group">
<input id="title" type="text" class="form-control" placeholder="请输入标题">
</div>
<div class="form-group">
<textarea name="" id="txt" cols="30" rows="5" class="form-control"></textarea>
</div>
<div class="form-group">
<input type="button" value="发布" class="btn btn-primary" id="btn-publish">
</div>
</form>
</div>
<div class="col-md-offset-3 col-md-6" id="content">
</div>
</div>
</div>
</body>
<script>
var oBtnPublish = document.getElementById("btn-publish");
var aTpl = [
'<div class="panel panel-success">',
'<div class="panel-heading">',
'<h4 class="panel-title">',
'<a href="javascript:;">',
'',
'</a>',
'</h4>',
'</div>',
'<div class="panel-body">',
'[content]',
'</div>',
'</div>'
];
var oContent = document.getElementById( "content" ),
str = aTpl.join( "" ),
title = '', content = '', panelParent = null;
oBtnPublish.onclick = function(){
str = aTpl.join( "" );
title = document.getElementById( "title" ).value;
txt = document.getElementById( "txt" ).value;
str = str.replace( /\/, title );
str = str.replace( /\[content\]/, txt );
oContent.innerHTML += str;
}
oContent.onclick = function( ev ){
var oEvent = ev || event;
var target = oEvent.target || oEvent.srcElement;
if ( target.tagName.toLowerCase() == 'a' ) {
panelParent = target.parentNode.parentNode.parentNode;
if ( panelParent.children[1].style.display == "block" || panelParent.children[1].style.display == '' ) {
panelParent.children[1].style.display = 'none';
} else {
panelParent.children[1].style.display = 'block';
}
}
}
</script>
</html>
作者:ghostwu, 出处:
www.cnblogs.com/ghostwu 博客大多数文章均属原创,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利