JavaScript(JQ)事件委託以及JS閉包小記

一開始看的時候有些暈,可以監聽DOM元素的方法太多,主要是寫在<script></script>,下面列出來理清楚:

JS原生:

document.getElementById("menuultest").onmouseover = function(ev){    };

JQ:該段參考自https://codeplayer.vip/p/j7sq1

// jQuery 1.0+ (1.4.3+支持參數data)
$("selector").click( [ data ,] handler );

// jQuery 1.0+ (1.4.3+支持參數data)
$("selector").bind( "click" [, data ], handler );

// jQuery 1.3+ (1.4+支持參數data)
$("selector").live( "click" [, data ], handler );

// jQuery 1.4.2+
$("ancestor").delegate( "selector", "click" [, data ], handler );

// jQuery 1.7+
$("ancestor").on( "click", "selector" [, data ], handler );

注:從jQuery 1.7開始,on()函數提供了綁定事件處理程序所需的所有功能,用於統一取代以前的bind()、 delegate()、 live()等事件函數。

==============================結束引用===========================

什麼是事件委託:

利用冒泡,只指定一個事件處理程序,就可以管理某一類型的所有事件。

事件委託和事件監聽的區別:

在js中,常用到element.addEventListener()來進行事件的監聽。但是當頁面中存在大量需要綁定事件的元素時,這種方式可能會帶來性能影響。此時,我們可以用事件委託的方式來進行事件的監聽,所以可以說事件委託是一種變相的事件監聽方式。

形象化事件委託:

想象公司有兩個員工要收快遞,有辦法是兩個人在公司門外等快遞送來或者是快遞員打電話到了再來拿,不考慮這兩種方法,那我們是不是可以想象公司前臺有人幫所有公司員工簽收,也就相當於委託公司前臺代收,然後員工再自己來取。

 接下來看看原生JS和JQ怎麼實現事件委託,先給出一段html:

<input type="button" name="" id="btn" value="添加" />
  <ul id = "menuultest">
     <li>
       <img src="images/btnimg01.jpg"></img>
       <a href="#">第一條</a>
     </li>
    
      <li>
       <img src="images/btnimg01.jpg"></img>
       <a href="#">第二條</a>
     </li>
  </ul>

一、JS實現點擊動態增加一行、鼠標經過效果有背景變化效果

var oBtn = document.getElementById("btn");
    var oUl = document.getElementById("menuultest");
    var aLi = oUl.getElementsByTagName('li');
    var num = 3;
    //添加新節點
            oBtn.onclick = function(){
                var oLi = document.createElement('li');
                oLi.innerHTML = '<li><img src="images/btnimg01.jpg"></img><a href="#">'+(111*num++)+'</a></li>'
                oUl.appendChild(oLi);
            };

            oUl.onclick = function(ev){
              e = ev || window.event;
              var target = e.target || e.srcElement;
              console.log(target.nodeName);
             if(target.nodeName == "A"){
                 console.log("點擊了a標籤");

              }else if(target.nodeName == "IMG"){
                 console.log("點擊了img標籤");
              }     
            }
            
            //事件委託,添加的子元素也有事件
            oUl.onmouseover = function(ev){
                var ev = ev || window.event;
                var target = ev.target || ev.srcElement;
                if(target.nodeName.toLowerCase() == 'li'){
                    target.style.background = "#FFEEFF";
                }
                
            };
            oUl.onmouseout = function(ev){
                var ev = ev || window.event;
                var target = ev.target || ev.srcElement;
                if(target.nodeName.toLowerCase() == 'li'){
                    target.style.background = "#fff";
                }
                
            };

二、JQ實現點擊動態增加一行、鼠標經過效果有背景變化效果

var num = 3;
    $("#btn").on('click',function(e){
       $("#menuultest").append('<li><img src="images/btnimg01.jpg"></img><a href="#">'+(111*num++)+'</a></li>')
    });

    $("#menuultest").on('click',function(e){
       e = e || window.event;
       var target = e.target || e.srcElement;
       console.log(target.nodeName);
       if(target.nodeName == "A"){
          console.log("點擊了a標籤");

       }else if(target.nodeName == "IMG"){
          console.log("點擊了img標籤");
       }
    });

$("#menuultest").on('mouseover',function(ev){
                var ev = ev || window.event;
                var target = ev.target || ev.srcElement;
                if(target.nodeName.toLowerCase() == 'li'){
                    target.style.background = "#FFEEFF";
                }
    });
    

    $("#menuultest").on('mouseout',function(ev){
                var ev = ev || window.event;
                var target = ev.target || ev.srcElement;
                if(target.nodeName.toLowerCase() == 'li'){
                    target.style.background = "#fff";
                }
    });

注:.bind的寫法也類似,不過還是推薦使用.on方法

$('#menuultest').bind('click', function (e) {
       e = e || window.event;
       var target = e.target || e.srcElement;
       console.log(target.nodeName);
       if(target.nodeName == "A"){
          console.log("點擊了a標籤");

       }else if(target.nodeName == "IMG"){
          console.log("點擊了img標籤");
       }
     });

三、JS閉包特性如何給循環中的對象添加事件

 本段參考自https://www.imooc.com/article/13833

初學者經常碰到的,即獲取HTML元素集合,循環給元素添加事件。在事件響應函數中(event handler)獲取對應的索引。但每次獲取的都是最後一次循環的索引,舉個例子:點擊所有的段落p輸出都是5,而不是alert出對應的0,1,2,3,4
 <!DOCTYPE HTML>
  <html>
  <head>
  <meta charset="utf-8" />
 <title>閉包演示</title>
  <style type="text/css">
      p {background:gold;}
  </style>
  <script type="text/javascript">
function init() {
    var pAry = document.getElementsByTagName("p");  
   for( var i=0; i<pAry.length; i++ ) {
        pAry[i].onclick = function() {
         alert(i);
   }
  }
}
</script>
</head>
<body onload="init();">
<p>產品 0</p>
<p>產品 1</p>
<p>產品 2</p>
<p>產品 3</p>
<p>產品 4</p>
</body>
</html>

即獲取HTML元素集合,循環給元素添加事件。在事件響應函數中(event handler)獲取對應的索引。但每次獲取的都是最後一次循環的索引。

通過element.onclick=function(){alert(i);}方式給元 素添加點擊事件。響應函數function(){alert(i);}中的 i 並非每次循環時對應的 i(如0,1,2,3,4)而是循環後最後 i 的值5。 或者說循環時響應函數內並未能保存對應的值 i,而是最後一次i++的值5。
瞭解了原因,下面就由幾種方式可與解決:

1、將變量 i 保存給在每個段落對象(p)上

<script> 
 function init1() {
    var pAry = document.getElementsByTagName("p");
    for( var i=0; i<pAry.length; i++ ) {
      pAry[i].i = i;
       pAry[i].onclick = function() {
          alert(this.i);
      }
    }
  }
</script>

2、加一層閉包,i 以函數參數形式傳遞給內層函數

  function init3() {
   var pAry = document.getElementsByTagName("p");
    for( var i=0; i<pAry.length; i++ ) {
     (function(arg){
         pAry[i].onclick = function() {
            alert(arg);
        };
     })(i);//調用時參數
    }
}

3、加一層閉包,i 以局部變量形式傳遞給內層函數

  function init4() {
   var pAry = document.getElementsByTagName("p");
    for( var i=0; i<pAry.length; i++ ) {
      (function () {
       var temp = i;//調用時局部變量
       pAry[i].onclick = function() {
          alert(temp);
        }
     })();
 }
}

4、加一層閉包,返回一個函數作爲響應事件(注意與3的細微區別)

  function init5() {
    var pAry = document.getElementsByTagName("p");
    for( var i=0; i<pAry.length; i++ ) {
     pAry[i].onclick = function(arg) {
         return function() {//返回一個函數
         alert(arg);
       }
     }(i);
    }
}

閉包的用途

閉包可以用在許多地方。它的最大用處有兩個,一個是前面提到的可以讀取函數內部的變量,另一個就是讓這些變量的值始終保持在內存中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章