可以添加代理事件,监听指定属性的指定动作,不依赖于节点结构,只依赖于冒泡冒上来的节点属性
先写好绑定事件的方法:
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 }
然后是正文:
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如下:
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);});