javascript 跨浏览器的事件系统4

上次说到我们在无菌环境中设计了一个事件代理函数,但性能是个问题,解决它我们需要缓存节点集合,发现节点集合不足以应对新情况时,再替换这个节点集合,重新开始匹配。下面是新的方案:

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);
}

好了,我们现在来考虑另一种情况。之前我们的判定都是用全等于来比较,但如果事件源是来自更底层的元素呢?换言之,是下面的情况。

<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);
}

我们再把筛选事件源的逻辑独立出来,就变成下面这个样子。是时候考虑如第一部分设计的事件系统衔接起来了!

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);
}
posted @ 2010-05-08 22:49  雨晴空  阅读(197)  评论(0编辑  收藏  举报