能夠添加代理事件,監聽指定屬性的指定動做,不依賴於節點結構,只依賴於冒泡冒上來的節點屬性 html
先寫好綁定事件的方法: node
1 var addEvent=function(node,type,fn){2 if(window.attachEvent){ 3 node.attachEvent("on"+type,fn); 4 } 5 else if(document.body.addEventListener){ 6 node.addEventListener(type,fn,false); 7 } 8 else node["on"+type]=fn;9 }
而後是正文: spa
var delegater = function(node) { var actions = {};//要監聽的自定義屬性 var types = {};//要監聽的事件類型開關 var that = {};//返回句柄 //從某節點向上循環,至node,返回這之間具備‘action’屬性的節點 var getTarget = function(el, type, action) { var nodeList = []; while(el.parentNode && el !== node) { if(el.getAttribute('action')) { nodeList.push(el); } el = el.parentNode; } return nodeList.length ? nodeList : null; } var dispatch = function(e, type) { var ev = e || window.event; var targets = getTarget(ev.target || ev.srcElement, type); //沒有要監聽的節點則返回 if(!targets) { return; }; //對每一個節點取一次action和data,傳入綁定的對應方法中 for(var i in targets) { var act = targets[i].getAttribute('action'); if(!actions[act]) { continue; } for(var k in actions[act]) { if(actions[act][k]['type'] == type) { //每一個對應方法都trycatch防止阻斷 try { actions[act][k]['fn']({ 'e' : e, 'el' : targets[i], 'type' : type, 'data' : targets[i].getAttribute('data') }); } catch(e) { } } } } } //外拋方法,添加對指定action的對事件type的監聽 that.add = function(action, type, fn) { actions[action] || (actions[action] = []); //加鎖,防止多重綁定和冗餘綁定 types[type] || (function() { types[type] = true; addEvent(node, type, function(e) { dispatch(e, type); }) })(); actions[action].push({ 'type' : type, 'fn' : fn }); } return that;}
測試html和js以下: .net
var h = delegater(document.getElementById('container'));h.add('level3a', 'click', function(obj) { console.log(obj);});h.add('level2a', 'click', function(obj) { console.log(obj);});h.add('level2b', 'click', function(obj) { console.log(obj);});h.add('level3a', 'mouseover', function(obj) { console.log(obj);});