作业帮 > ASP.NET > 教育资讯

asp.net技巧:如何理解与简化jquery的closest函数

来源:学生作业帮助网 编辑:作业帮 时间:2024/04/28 00:05:25 ASP.NET
asp.net技巧:如何理解与简化jquery的closest函数
asp.net技巧:如何理解与简化jquery的closest函数ASP.NET
【无忧考网-asp技巧:如何理解与简化jquery的closest函数】:

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

closest: function( selectors, context ) { 

    var ret = [], i, l, cur = this[0]; 

      

    // Array 

    if ( jQuery.isArray( selectors ) ) {//这分支的过滤逻辑基本与下面的一致 

        var match, selector, 

            matches = {}, 

            level = 1; 

 

        if ( cur && selectors.length ) { 

            for ( i = 0, l = selectors.length; i < l; i++ ) { 

                selector = selectors[i]; 

 

                if ( !matches[ selector ] ) { 

                    matches[ selector ] = POS.test( selector ) ? 

                        jQuery( selector, context || this.context ) : 

                        selector; 

                } 

            } 

 

            while ( cur && cur.ownerDocument && cur !== context ) { 

                for ( selector in matches ) { 

                    match = matches[ selector ];//这里频繁创建新的jQuery对象与使用is这样复杂的方法,我不觉得其高效到哪里去 

 

                    if ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) { 

                        ret.push({ selector: selector, elem: cur, level: level }); 

                    } 

                } 

 

                cur = cur.parentNode; 

                level++; 

            } 

        } 

 

        return ret; 

    } 

 

    // String 

    var pos = POS.test( selectors ) || typeof selectors !== "string" ? 

            jQuery( selectors, context || this.context ) : 

            0; 

 

    for ( i = 0, l = this.length; i < l; i++ ) { 

        cur = this[i]; 

 

        while ( cur ) { 

            if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { 

                ret.push( cur ); 

                break; 

 

            } else { 

                cur = cur.parentNode; 

                if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { 

                    break; 

                } 

            } 

        } 

    } 

 

    ret = ret.length > 1 ? jQuery.unique( ret ) : ret; 

 

    return this.pushStack( ret, "closest", selectors ); 

},

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

closest: function( selectors, context ) { 

    var ret = [], i, l, cur = this[0]; 

     

    // 如果字符串包含位置伪类或者是个元素节点,则封装为一个jQuery对象,否则为0(即false的简写,用于快速跳过分支) 

    var pos = POS.test( selectors ) || typeof selectors !== "string" ? 

        jQuery( selectors, context || this.context ) : 

        0; 

    //遍历原jQuery对象的节点 

    for ( i = 0, l = this.length; i < l; i++ ) { 

        cur = this[i]; 

  

        while ( cur ) { 

            //如果是jQuery对象,则判定其是否包含当前节点,否则使用matchesSelector方法判定这个节点是否匹配给定的表达式selectors 

            if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { 

                //是则放入选择器中 

                ret.push( cur ); 

                break; 

  

            } else { 

                //  否则把当前节点变为其父节点 

                cur = cur.parentNode; 

                if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { 

                    break; 

                } 

            } 

        } 

    } 

    //如果大于1,进行唯一化操作 

    ret = ret.length > 1 ? jQuery.unique( ret ) : ret; 

    //将节点集合重新包装成一个新jQuery对象返回 

    return this.pushStack( ret, "closest", selectors ); 

},

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

closest: function( selectors ) { 

    var ret = [], i, l, cur = this[0]; 

    // 如果字符串包含位置伪类或者是个元素节点,则封装为一个jQuery对象,否则为0(即false的简写,用于快速跳过分支) 

    var node =  selectors.nodeType ? selectors :false; 

    var nodes = [].slice.call(this);//将jQuery对象转换为纯数组 

    //遍历原jQuery对象的节点 

    for ( i = 0, l = this.length; i < l; i++ ) { 

        cur = this[i]; 

  

        while ( cur ) { 

            //如果是jQuery对象,则判定其是否包含当前节点,否则使用matchesSelector方法判定这个节点是否匹配给定的表达式selectors 

            if ( obj ? nodes.indexOf(node) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { 

                //indexOf方法在某些浏览器需要自行实现 

                //是则放入选择器中 

                ret.push( cur ); 

                break; 

            } else { 

                //  否则把当前节点变为其父节点 

                cur = cur.parentNode; 

                //如果没有父节点(说明其还没有插入DOM树),或不是元素节点,或是文档碎片(说明其刚被移出DOM树) 

                if ( !cur || !cur.ownerDocument || cur.nodeType === 11 ) { 

                    break; 

                } 

            } 

        } 

    } 

    //如果大于1,进行唯一化操作 

    ret = ret.length > 1 ? jQuery.unique( ret ) : ret; 

    //将节点集合重新包装成一个新jQuery对象返回 

    return $(ret);//本人觉得pushStack真是个邪恶的方法,让菜鸟不籽有链下去的欲望,殊不知这是维护的大敌 

},

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

 

 

   

    closest在jquery1.6的改变 by 司徒正美 

     

     

  

   

   

   

 

      使用事件代理1 

   

 

   

 

      使用事件代理2 

   

 

   

 

      使用事件代理3 

   

 

   

下面是我的实现:

closest: function( exPR ) { 

    // 如果字符串包含位置伪类或者是个元素节点,则封装为一个dom对象,否则为0(即false的简写,用于快速跳过分支) 

    var node =  expr.nodeType ? expr : 0, nodes = dom.slice(this);//将它转换为纯数组 

    //遍历原dom对象的节点 

    for (var i = 0, ret = [], cur; cur = this[i++];) {//由于肯定里面都是节点,因此可以使用这种循环 

        while (cur && cur.nodeType === 1 ) { 

            //如果是dom对象,则判定其是否包含当前节点,否则使用matchesSelector方法判定这个节点是否匹配给定的表达式expr 

            if ( node ? nodes.indexOf(node) > -1 : matchElement( cur, expr ) ){ 

                //indexOf方法在某些浏览器需要自行实现 

                //是则放入选择器中 

                ret.push( cur ); 

                break; 

            } else { 

                // 否则把当前节点变为其父节点 

                cur = cur.parentNode; 

            } 

        } 

    } 

    //如果大于1,进行唯一化操作 

    ret = ret.length > 1 ? dom.unique( ret ) : ret; 

    //将节点集合重新包装成一个新dom对象返回 

    return this.labor(ret); 

},

ASP.NET