如何理解与简化jQuery的closest函数

在实现delegate方法中,有一个很重要的辅助函数叫closest,虽然现在它归类为遍历节点这个模块中。这个函数实现得非常复杂,洋洋洒洒近50行,完全不符合极限编程的规矩。

成都创新互联-专业网站定制、快速模板网站建设、高性价比台江网站开发、企业建站全套包干低至880元,成熟完善的模板库,直接使用。一站式台江网站制作公司更省心,省钱,快速模板网站建设找我们,业务覆盖台江地区。费用合理售后完善,十年实体公司更值得信赖。

 
 
 
  1. closest: function( selectors, context ) {     
  2.     var ret = [], i, l, cur = this[0];    
  3.     // Array    
  4.     if ( jQuery.isArray( selectors ) ) {//这分支的过滤逻辑基本与下面的一致  
  5.         var match, selector,  
  6.             matches = {},    
  7.             level = 1;    
  8.         if ( cur && selectors.length ) {    
  9.             for ( i = 0, l = selectors.length; i < l; i++ ) {    
  10.                 selector = selectors[i];    
  11.                 if ( !matches[ selector ] ) {    
  12.                     matches[ selector ] = POS.test( selector ) ?    
  13.                         jQuery( selector, context || this.context ) :    
  14.                       selector;    
  15.                 }    
  16.             }    
  17.             while ( cur && cur.ownerDocument && cur !== context ) {  
  18.                 for ( selector in matches ) {    
  19.                     match = matches[ selector ];//这里频繁创建新的jQuery对象与使用is这样复杂的方法,我不觉得其高效到哪里去    
  20.                     if ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) {    
  21.                         ret.push({ selector: selector, elem: cur, level: level });    
  22.                     }    
  23.                 }    
  24.                 cur = cur.parentNode;    
  25.                 level++;    
  26.             }    
  27.         }    
  28.         return ret;    
  29.     }  
  30.     // String     
  31.     var pos = POS.test( selectors ) || typeof selectors !== "string" ?    
  32.             jQuery( selectors, context || this.context ) :    
  33.             0;    
  34.     for ( i = 0, l = this.length; i < l; i++ ) {    
  35.         cur = this[i];    
  36.         while ( cur ) {    
  37.             if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {    
  38.                 ret.push( cur );    
  39.                 break;  
  40.             } else {    
  41.                 cur = cur.parentNode;    
  42.                 if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {    
  43.                    break;    
  44.                 }    
  45.             }    
  46.         }     
  47.     }  
  48.     ret = ret.length > 1 ? jQuery.unique( ret ) : ret;    
  49.     return this.pushStack( ret, "closest", selectors );    
  50. },   

恰逢我也想造个轮子,便去研究它一翻,发现其***个可以是字符串,元素节点或jQuery对象,还有一个可选参数,上下文。看源码前几句,发现有个分支是判断是否是Array,估计是供内部调用的优化代码,可以无视之。于是其方法简化为:

 
 
 
  1. closest: function( selectors, context ) {    
  2.     var ret = [], i, l, cur = this[0];    
  3.     // 如果字符串包含位置伪类或者是个元素节点,则封装为一个jQuery对象,否则为0(即false的简写,用于快速跳过分支)    
  4.     var pos = POS.test( selectors ) || typeof selectors !== "string" ?    
  5.         jQuery( selectors, context || this.context ) :    
  6.         0;    
  7.     //遍历原jQuery对象的节点    
  8.     for ( i = 0, l = this.length; i < l; i++ ) {    
  9.         cur = this[i];    
  10.         while ( cur ) {    
  11.             //如果是jQuery对象,则判定其是否包含当前节点,否则使用matchesSelector方法判定这个节点是否匹配给定的表达式selectors    
  12.             if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {    
  13.               //是则放入选择器中    
  14.                 ret.push( cur );    
  15.                 break;   
  16.             } else {    
  17.                 //  否则把当前节点变为其父节点    
  18.                 cur = cur.parentNode;    
  19.                 if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {    
  20.                     break;    
  21.                 }    
  22.             }    
  23.         }    
  24.     }    
  25.     //如果大于1,进行唯一化操作    
  26.     ret = ret.length > 1 ? jQuery.unique( ret ) : ret;    
  27.     //将节点集合重新包装成一个新jQuery对象返回    
  28.     return this.pushStack( ret, "closest", selectors );    
  29. },  

由于本人很反感位置伪类,认为其违反选择器的法则之一(由关系选择器隔开的各选择器分组内部,它们的位置是随意的),因此有关位置伪类的逻辑我也去掉了。

 
 
 
  1. closest: function( selectors ) {    
  2.     var ret = [], i, l, cur = this[0];    
  3.     // 如果字符串包含位置伪类或者是个元素节点,则封装为一个jQuery对象,否则为0(即false的简写,用于快速跳过分支)    
  4.     var node =  selectors.nodeType ? selectors :false;    
  5.     var nodes = [].slice.call(this);//将jQuery对象转换为纯数组    
  6.     //遍历原jQuery对象的节点    
  7.     for ( i = 0, l = this.length; i < l; i++ ) {    
  8.         cur = this[i];   
  9.         while ( cur ) {    
  10.             //如果是jQuery对象,则判定其是否包含当前节点,否则使用matchesSelector方法判定这个节点是否匹配给定的表达式selectors    
  11.             if ( obj ? nodes.indexOf(node) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {    
  12.                 //indexOf方法在某些浏览器需要自行实现    
  13.                 //是则放入选择器中    
  14.                 ret.push( cur );    
  15.                 break;    
  16.             } else {    
  17.                 //  否则把当前节点变为其父节点    
  18.                 cur = cur.parentNode;    
  19.                 //如果没有父节点(说明其还没有插入DOM树),或不是元素节点,或是文档碎片(说明其刚被移出DOM树)    
  20.                 if ( !cur || !cur.ownerDocument || cur.nodeType === 11 ) {    
  21.                     break;    
  22.                 }    
  23.             }    
  24.         }    
  25.     }    
  26.     //如果大于1,进行唯一化操作    
  27.     ret = ret.length > 1 ? jQuery.unique( ret ) : ret;    
  28.     //将节点集合重新包装成一个新jQuery对象返回    
  29.     return $(ret);//本人觉得pushStack真是个邪恶的方法,让菜鸟不籽有链下去的欲望,殊不知这是维护的大敌    
  30. },  

注意,jquery1.6中closest方法不再是返回包含一个或零个节点的jQuery对象了,再是对应多个了(因此jQuery官网文档是错误的,没有即时同步这变化.)

 
 
 
  1.     
  2.  
  3.     
  4.       
  5.     closest在jquery1.6的改变 by 司徒正美    
  6.         
  7.         
  8.       
  9.       
  10.     

        

  11.       使用事件代理1    
  12.     

        
  13.     

        

  14.      使用事件代理2    
  15.     

        
  16.     

        

  17.       使用事件代理3    
  18.     

        
  19.       
  20.   

下面是我的实现:

 
 
 
  1. closest: function( expr ) {    
  2.     // 如果字符串包含位置伪类或者是个元素节点,则封装为一个dom对象,否则为0(即false的简写,用于快速跳过分支)    
  3.     var node =  expr.nodeType ? expr : 0, nodes = dom.slice(this);//将它转换为纯数组    
  4.     //遍历原dom对象的节点    
  5.     for (var i = 0, ret = [], cur; cur = this[i++];) {//由于肯定里面都是节点,因此可以使用这种循环    
  6.         while (cur && cur.nodeType === 1 ) {    
  7.             //如果是dom对象,则判定其是否包含当前节点,否则使用matchesSelector方法判定这个节点是否匹配给定的表达式expr    
  8.             if ( node ? nodes.indexOf(node) > -1 : matchElement( cur, expr ) ){    
  9.                 //indexOf方法在某些浏览器需要自行实现    
  10.                 //是则放入选择器中    
  11.                 ret.push( cur );    
  12.                 break;    
  13.             } else {    
  14.                 // 否则把当前节点变为其父节点    
  15.                 cur = cur.parentNode;    
  16.             }    
  17.         }    
  18.     }    
  19.     //如果大于1,进行唯一化操作    
  20.     ret = ret.length > 1 ? dom.unique( ret ) : ret;    
  21.     //将节点集合重新包装成一个新dom对象返回    
  22.     return this.labor(ret);    
  23. },  

原文链接:http://www.cnblogs.com/rubylouvre/archive/2011/05/12/2043854.html

【编辑推荐】

  1. 详解jQuery构造器的实现
  2. jQuery调用WCF开发实例经验分享
  3. 5月***超有趣的免费jQuery插件推荐
  4. 手把手教你使用jQuery操作元素的属性与样式
  5. jQuery性能指标和调优

新闻标题:如何理解与简化jQuery的closest函数
当前链接:http://www.stwzsj.com/qtweb/news38/13188.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联