文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>如果简化与理解jquery的closest函数

如果简化与理解jquery的closest函数

时间:2011-05-12  来源:司徒正美

在实现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 ];

                                                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真是个邪恶的方法,让菜鸟不籽有链下去的欲望,殊不知这是维护的大敌
},

下面是我的实现:

            closest: function( expr ) {
                // 如果字符串包含位置伪类或者是个元素节点,则封装为一个dom对象,否则为0(即false的简写,用于快速跳过分支)
                var node =  expr.nodeType ? expr : 0, nodes = dom.slice(this);//将jQuery对象转换为纯数组
                //遍历原dom对象的节点
                for (var i = 0, ret = [], cur; cur = this[i++];) {
                    while (cur && cur.nodeType === 1 ) {
                        //如果是dom对象,则判定其是否包含当前节点,否则使用matchesSelector方法判定这个节点是否匹配给定的选择器selectors
                        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;
                //将节点集合重新包装成一个新jQuery对象返回
                return this.labor(ret);
            },
相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载