javascript事件代理


在編程中,若是咱們不想或不可以直接操縱目標對象,咱們能夠利用delegate建立一個代理對象來調用目標對象的方法,從而達到操縱目標對象的目的。毋庸置疑,代理對象要擁有目標對象的引用。咱們來看一下javascript的一個最簡單實現:javascript

vardelegate =function(client,clientMethod ){
  returnfunction() {returnclientMethod.apply(client,arguments); }
}
varagentMethod = delegate(client, client.method )
agentMethod();
<!doctype html>
<html dir="ltr" lang="zh-CN">
  <head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge">
    <script type="text/javascript">
      var ClassA = function(){
        var _color = "red";
        return {
          getColor : function(){
            document.write("<p>ClassA的實例的私有屬性_color目前是<span style='color:"+_color+"' >"+_color+"</span></p>");
          },
          setColor:function(color){
            _color = color;
          }
        };
      };
      var delegate = function (client,clientMethod ){
        return function() { return clientMethod.apply(client,arguments); }
      }
      window.onload = function(){
        var a = new  ClassA();
        a.getColor();
        a.setColor("green");
        a.getColor();
        //alert(a._color);
        document.write("<p>執行代理!</p>")
        var d = delegate(a,a.setColor);
        d("blue");
        document.write("<p>執行完畢!</p>")
        a.getColor();
      };
    </script>
    <title>delegate</title>
  </head>
  <body>
  </body>
</html>



或者咱們改變一下第二個參數,傳個字符串進去:php

      vardelegate =function(client,clientMethod ){
        returnfunction() {returnclient[clientMethod].apply(client,arguments); }
      }
/****************略*******************/
     vard = delegate(a,"setColor");

咱們還能夠搞一些很好玩的東西,下面的例子取自一個日本博客css

<script type="text/javascript">
     Function.prototype.delegate = function(delegateFor){
    return delegateFor.apply(null, arguments);
};

var Hoge = function(){
    this.open = function (){
        return 'this is Hoge#open';
    };
    this.close = function (){
        return 'this is Hoge#close';
    };
};
var Foo = function (){
    this.name = 'foo';
    this.open = function (){
        return 'this is Foo#open';
    };
    this.close = function (){
        return 'this is Foo#close';
    };
};

var hoge = new Hoge;
var foo = new Foo;

alert(hoge.open()); // this is Hoge#open
alert(hoge.open.delegate(foo.open)); // this is Foo#open
alert(foo.open.delegate(hoge.open)); // this is Hoge#open
</script>

因爲delegate實現目標對象的隱藏,這對於咱們保護一些核心對象是很是有用的。不過,說實在javascript的delegate基本算是call與apply的傀儡,由於js中只有這2個方法提供了改變當前函數內部this做用域的功能。不過,要實現對類的委託而不是實例的委託,這就複雜得多。Prototype.js,YUI與JQuery都有相應的實現。具體本身可去參考它們的源碼。接着下來,我將講述delegate在事件上的應用,這但是個無以倫比的東東,就是改變偵聽器的位置(改變事件的綁定對象)。或者說,它得益於javascript獨特的事件傳播機制,所以實現起來很是容易,你們要好好運行它,我之前也在富文本編輯器中用過。html

$.addEvent(colorPicker,'click',function(){
  vare = arguments[0] || window.event,
  td = e.srcElement ? e.srcElement : e.target,
  nn = td.nodeName.toLowerCase();
  if(nn =='td'){
    varcmd = colorPicker.getAttribute("title");
    varval = td.bgColor;
    _format(cmd,val);
    e.cancelBubble =true;
    colorPicker.style.display ='none';
  }
});

上面就是我在富文本編輯器擷取前景色與背景色的代碼,注意,我是把事件綁定在顏色面板上,而不是面板上的那一個個格子上。爲了直觀起見,便於你們操做,我改用下面這個例子:java

<ulid="nav">
      <li><ahref="http://www.cnblogs.com/">博客園</a></li>
      <li><ahref="http://www.w3school.com.cn/">W3School</a></li>
      <li><ahref="http://study.163.com/">網易雲課堂</a></li>
      <li><ahref="http://www.willspace.cn/">WILLSpace</a></li>
      <li><ahref="http://blog.csdn.net/willspace/">CSDN_WILLSpace</a></li>
</ul>

如今咱們要點擊列表中連接,取出裏面的內容,傳統的方法,咱們須要遍歷添加全部a元素:node

window.onload =function(){
   varnav = document.getElementById("nav");
   varlinks = nav.getElementsByTagName("a");
   for(vari=0,l = links.length; i<l; i++) {
     links[i].onclick =function() {
       alert(this.innerHTML);
       returnfalse;
     }
   }
 }
<!doctype html>
<html dir="ltr" lang="zh-CN">
  <head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge">
    <style type="text/css">
      body{background:#fff;}
      a { color:#8080C0;text-decoration:none;border-bottom:2px solid #fff;}
      a:hover {color:#336699;border-bottom-color:#B45B3E;}
    </style>
    <script type="text/javascript">
      window.onload = function(){
        var nav = document.getElementById("nav");
        var links = nav.getElementsByTagName("a");
        for (var i=0,l = links.length; i <l; i++) {
          links[i].onclick = function () {
            alert(this.innerHTML);
            return false; 
          }
        }
      }    
    </script>
    <title>delegate</title>
  </head>
  <body>
    <ul id="nav">
      <li><a href="http://www.cnblogs.com/">博客園</a></li>
      <li><a href="http://www.w3school.com.cn/">W3School</a></li>
      <li><a href="http://study.163.com/">網易雲課堂</a></li>
      <li><a href="http://www.willspace.cn/">WILLSpace</a></li>
      <li><a href="http://blog.csdn.net/willspace/">CSDN_WILLSpace</a></li>
    </ul>
  </body>
</html>


新的方法,用nav代理了它下面全部元素,讓它負責你們的onclick事件,包括它本身的,也無論是否爲a元素,因此有時咱們須要作一些判斷,但少了遍歷DOM樹,效率明顯提升。jquery

window.onload =function(){
  varnav = document.getElementById("nav");
  nav.onclick =function() {
    vare = arguments[0] || window.event,
    target = e.srcElement ? e.srcElement : e.target;
    alert(target.innerHTML);
    returnfalse;
  }
}
 
<!doctype html>
<html dir="ltr" lang="zh-CN">
  <head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge">
    <style type="text/css">
      body{background:#fff;}
      a { color:#8080C0;text-decoration:none;border-bottom:2px solid #fff;}
      a:hover {color:#336699;border-bottom-color:#B45B3E;}
    </style>
    <script type="text/javascript">
      window.onload = function(){
        var nav = document.getElementById("nav");
        nav.onclick = function () {
          var e = arguments[0] || window.event,
          target = e.srcElement ? e.srcElement : e.target;
          alert(target.innerHTML);
          return false;
        }
      }
    </script>
    <title>delegate</title>
  </head>
  <body>
    <ul id="nav">
      <li><a href="http://www.cnblogs.com/">博客園</a></li>
      <li><a href="http://www.w3school.com.cn/">W3School</a></li>
      <li><a href="http://study.163.com/">網易雲課堂</a></li>
      <li><a href="http://www.willspace.cn/">WILLSpace</a></li>
      <li><a href="http://blog.csdn.net/willspace/">CSDN_WILLSpace</a></li>
    </ul>
  </body>
</html>

爲何它會行得通呢?!由於DOM2.0的事件模型是這樣的,若是某個元素觸發一個事件,如onclick,頂層對象document就會發出一個事件流,隨着DOM樹往目標元素流去,這就是傳說中的捕獲階段,也就是原Netscape的事件執行模式,沿途的元素若是綁定了事件,它是不會執行的!第二階段,就是到達了目標元素,執行它上面的綁定事件,但若是onclick只是個空實現,固然是沒有效果啦!第三階級,就是起泡階級,原IE的事件執行模式,從目標元素往頂層元素折回,若是沿途有onclick事件,就隨個觸發!所以咱們是點擊了a元素,但它的onclick事件爲空,當事件流上浮到ul元素時,發現ul元素綁定了onclick事件,就執行當中的函數。若是ul的祖先元素也綁定了onclick事件呢?!繼續執行!有多少執行多少!看下面的例子:web

 
<!doctype html>
<html dir="ltr" lang="zh-CN">
  <head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge">
    <style type="text/css">
      body{background:#fff;}
      a { color:#8080C0;text-decoration:none;border-bottom:2px solid #fff;}
      a:hover {color:#336699;border-bottom-color:#B45B3E;}
    </style>
    <script type="text/javascript">
      var addEvent = (function () {
        if (document.addEventListener) {
          return function (el, type, fn) {
            el.addEventListener(type, fn, false);
          };
        } else {
          return function (el, type, fn) {
            el.attachEvent('on' + type, function () {
              return fn.call(el, window.event);
            });
          }
        }
      })();

      window.onload = function(){
        var nav = document.getElementById("nav");
        nav.onclick = function () {
          var e = arguments[0] || window.event,
          target = e.srcElement ? e.srcElement : e.target;
          alert(target.innerHTML);
          return false;
        }
        var wrapper = document.getElementById("wrapper");
        addEvent(wrapper,'click',function(){
          alert("冒泡過程連我也驚動了!");
        });
      }
    </script>
    <title>delegate</title>
  </head>
  <body>
    <div id="wrapper">
      <ul id="nav">
        <li><a href="http://www.cnblogs.com/">博客園</a></li>
        <li><a href="http://www.w3school.com.cn/">W3School</a></li>
        <li><a href="http://study.163.com/">網易雲課堂</a></li>
        <li><a href="http://www.willspace.cn/">WILLSpace</a></li>
        <li><a href="http://blog.csdn.net/willspace/">CSDN_WILLSpace</a></li>
      </ul>
    </div>
  </body>
</html>
   

正因爲這個特性,咱們就能夠利用ul的onclick去代理它下面全部元素的onclick事件。原來,咱們須要給這些a元素準備五個偵聽器(EventListener),如今咱們只須要1個,節省了4個,若是這個列表有一百行呢?就節省了99個!在商務應用,咱們通過會遇到許多報表(grid,實質是用table作的),咱們須要爲每行添加懸浮變色效果與點擊編輯功能,這就用到onmouseover 、 onmouseout 與 onclick事件,若是這個報表有五千行,咱們也只須要三個偵聽器,節省了14997個!若是用傳統方法作這個grid,IE6這樣垃圾的遊覽器不卡到你吐血。所以,善用event delegation會大大提升咱們程序的性能。編程

附上一些有用的連接:ruby

文章轉自:
http://www.cnblogs.com/rubylouvre/archive/2009/08/09/1542174.html
感謝做者
相關文章
相關標籤/搜索