javascript 跨瀏覽器的事件系統4

來源:互聯網
上載者:User

上次說到我們在無菌環境中設計了一個事件代理函數,但效能是個問題,解決它我們需要緩衝節點集合,發現節點集合不足以應對新情況時,再替換這個節點集合,重新開始匹配。下面是新的方案:

         var delegate = function(selector,type,callback){          var els = $(selector);          addEvent(document,type,function(e){            var flag = true;            var node = e.srcElement || e.target;            for(var i=0,el;el = els[i++];){              if(node === el){                flag = false;                return callback.call(node,e);              }            }            if(flag){              els = $(selector);              for(var i=0,el;el = els[i++];){                if(node === el){                  return callback.call(node,e);                }              }            }          },true);        }

<br /><!doctype html><br /><html lang="zh-ch" id="html"><br /> <head><br /> <meta charset="utf-8" /><br /> <meta content="IE=8" http-equiv="X-UA-Compatible"/><br /> <title>事件代理 by 司徒正美</title></p><p> <script type="text/javascript"><br /> window.onload = function(){<br /> var addEvent = function(el,type,callback,data){<br /> if ( el.addEventListener ) {//如自訂對象就綁定回呼函數了<br /> el.addEventListener( type, callback, !!data );<br /> } else if ( el.attachEvent ) {<br /> el.attachEvent( "on" + type, function(){<br /> return callback.call(el,window.event)<br /> });<br /> }<br /> }<br /> var delegate = function(selector,type,callback){<br /> var els = $(selector);<br /> addEvent(document,type,function(e){<br /> var flag = true;<br /> var node = e.srcElement || e.target;<br /> for(var i=0,el;el = els[i++];){<br /> if(node === el){<br /> flag = false;<br /> return callback.call(node,e);<br /> }<br /> }<br /> if(flag){<br /> els = $(selector);<br /> for(var i=0,el;el = els[i++];){<br /> if(node === el){<br /> return callback.call(node,e);<br /> }<br /> }<br /> }<br /> },true);<br /> }<br /> delegate("#list li","click",function(e){<br /> alert(this.innerHTML+e.type)<br /> });<br /> }<br /> var $ = function(selector,context){<br /> context = context || document<br /> try{<br /> var els = context.querySelectorAll(selector),<br /> result = [],ri=0,i=0,n=els.length;<br /> for(;i<n;i++){<br /> result[ri++] = els[i]<br /> }<br /> return result;<br /> }catch(e){<br /> alert("你的瀏覽器不支援querySelectorAll")<br /> }<br /> }<br /> var aaa = function(){<br /> var li = document.createElement("li");<br /> li.innerHTML = "動態添加"+aaa.aa++<br /> $("#list")[0].appendChild(li)<br /> }<br /> aaa.aa = 0;<br /> </script></p><p> </head><br /> <body id="body"><br /> <h1>司徒正美:事件代理</h1><br /> <ul id="list"><br /> <li>無序列表1</li><br /> <li>無序列表2</li><br /> <li>無序列表3</li><br /> <li>無序列表4</li><br /> </ul><br /> <p>下面的無序列表是沒有id的!</p><br /> <ul><br /> <li>無序列表1</li><br /> <li>無序列表2</li><br /> <li>無序列表3</li><br /> <li>無序列表4</li><br /> </ul><br /> <button type="button" onclick="aaa()">動態添加</button></p><p> </body><br /></html><br />

運行代碼

好了,我們現在來考慮另一種情況。之前我們的判定都是用全等於來比較,但如果事件來源是來自更底層的元素呢?換言之,是下面的情況。

     <div onclick="alert('outer')" id="outer">      <div onclick="alert('middle')" id="middle">        <div onclick="alert('inner')" id="inner"></div>      </div>    </div>

當我們點擊inner元素時,它上面的middle與outer的onclick也觸發,因此我們必須引入包含判定了。這裡我直接給出答案,具體可見我的這一篇博文。

       var  contains = function(el, root) {        if (el.compareDocumentPosition)          return (el.compareDocumentPosition(root) & 8) === 8;        if (root.contains && el.nodeType === 1){          return root.contains(el) && root !== el;        }        while ((el = el.parentNode))          if (el === root) return true;        return false;      }      var delegate = function(selector,type,callback){        var els = $(selector);        addEvent(document,type,function(e){          var flag = true;          var src = e.srcElement || e.target;          for(var i=0,el;el = els[i++];){            if(el === src || contains(src,el) ){              flag = false;              return callback.call(el,e);            }          }          if(flag){            els = $(selector);            for(var i=0,el;el = els[i++];){              if(el === src || contains(src,el) ){                return callback.call(el,e);              }            }          }        },true);      }

<br /><!doctype html><br /><html lang="zh-ch" id="html"><br /> <head><br /> <meta charset="utf-8" /><br /> <meta content="IE=8" http-equiv="X-UA-Compatible"/><br /> <title>事件代理 by 司徒正美</title></p><p> <script type="text/javascript"><br /> window.onload = function(){<br /> var addEvent = function(el,type,callback,data){<br /> if ( el.addEventListener ) {//如自訂對象就綁定回呼函數了<br /> el.addEventListener( type, callback, !!data );<br /> } else if ( el.attachEvent ) {<br /> el.attachEvent( "on" + type, function(){<br /> return callback.call(el,window.event)<br /> });<br /> }<br /> }<br /> var delegate = function(selector,type,callback){<br /> var els = $(selector);<br /> addEvent(document,type,function(e){<br /> var flag = true;<br /> var src = e.srcElement || e.target;<br /> for(var i=0,el;el = els[i++];){<br /> if(el === src || contains(src,el) ){<br /> flag = false;<br /> return callback.call(el,e);<br /> }<br /> }<br /> if(flag){<br /> els = $(selector);<br /> for(var i=0,el;el = els[i++];){<br /> if(el === src || contains(src,el) ){<br /> return callback.call(el,e);<br /> }<br /> }<br /> }<br /> },true);<br /> }<br /> delegate("#list li","click",function(e){<br /> alert(this.innerHTML+e.type)<br /> });<br /> }<br /> var $ = function(selector,context){<br /> context = context || document<br /> try{<br /> var els = context.querySelectorAll(selector),<br /> result = [],ri=0,i=0,n=els.length;<br /> for(;i<n;i++){<br /> result[ri++] = els[i]<br /> }<br /> return result;<br /> }catch(e){<br /> alert("你的瀏覽器不支援querySelectorAll")<br /> }<br /> }<br /> var contains = function(el, root) {<br /> if (el.compareDocumentPosition)<br /> return (el.compareDocumentPosition(root) & 8) === 8;<br /> if (root.contains && el.nodeType === 1){<br /> return root.contains(el) && root !== el;<br /> }<br /> while ((el = el.parentNode))<br /> if (el === root) return true;<br /> return false;<br /> }<br /> var aaa = function(){<br /> var li = document.createElement("li");<br /> li.innerHTML = "動態添加"+aaa.aa++<br /> $("#list")[0].appendChild(li)<br /> }<br /> aaa.aa = 0;<br /> </script><br /> <style type="text/css"><br /> #inner{<br /> padding:10px;<br /> width:50px;<br /> height:50px;<br /> background:#4DC2F2;<br /> }<br /> #middle{<br /> padding:10px;<br /> width:100px;<br /> height:100px;<br /> background:#FF98ED;<br /> }<br /> #outer{<br /> padding:10px;<br /> width:150px;<br /> height:150px;<br /> background:#00FF00<br /> }<br /> </style><br /> </head><br /> <body id="body"><br /> <h1>司徒正美:事件代理</h1><br /> <ul id="list"><br /> <li>無序列表1</li><br /> <li>無序列表2</li><br /> <li>無序列表3</li><br /> <li>無序列表4</li><br /> </ul><br /> <p>下面的無序列表是沒有id的!</p><br /> <ul><br /> <li>無序列表1</li><br /> <li>無序列表2</li><br /> <li>無序列表3</li><br /> <li>無序列表4</li><br /> </ul><br /> <button type="button" onclick="aaa()">動態添加</button><br /> <div onclick="alert('outer')" id="outer"><br /> <div onclick="alert('middle')" id="middle"><br /> <div onclick="alert('inner')" id="inner"></div><br /> </div><br /> </div><br /> </body><br /></html><br />

運行代碼

我們再把篩選事件來源的邏輯獨立出來,就變成下面這個樣子。是時候考慮如第一部分設計的事件系統銜接起來了!

         var handle = function(e,obj){          var flag = true,           src = e.srcElement || e.target,          els = obj.nodes;          for(var i=0,el;el = els[i++];){            if(el === src || contains(src,el) ){              flag = false;              return obj.callback.call(el,e);            }          }          if(flag){            els = obj.nodes = $(obj.selector);            for(var i=0,el;el = els[i++];){              if(el === src || contains(src,el) ){                return obj.callback.call(el,e);              }            }          }        }        var delegate = function(selector,type,callback){          var handleObj = {};          handleObj.callback = callback;          handleObj.selector = selector;          handleObj.nodes = $(selector);          addEvent(document,type,function(e){            handle(e,handleObj)          },true);        }

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.