• 关于js封装框架类库之选择器引擎(二)


    在上篇介绍了选择器的获取标签、id、类名的方法,现在我们在上篇基础上继续升级

    1、问题描述:上篇get('选择器')已经实现,如果get方法里是一个选择器的父元素,父元素是DOM对象,那么如何获取元素

    思路:1、首先想到的是标签、id、类名的三个方法  2、假设是body节点,那么方法中的document改成body 3、传入的参数如何判断是否为DOM

    注意:在获取id方法中全局也只有一个id,所以其中的doument无须修改

    修改如下

    // 注释: 对获取DOM对象方法的封装
    var getTag = function ( tag, context, results ) {
        results = results || [];
        context = context || document;//防止context是空时报错现象出现
        
        results.push.apply( results, context.getElementsByTagName( tag ) );
        return results;
    };
    
    var getId = function ( id, results ) {
        results = results || [];
        results.push( document.getElementById( id ) );
        return results;
    };
    
    var getClass = function ( className, context, results ) {
        results = results || [];
        context = context || document;
        if ( document.getElementsByClassName ) {
            results.push.apply( results, context.getElementsByClassName( className ) );
        } else {
            each( getTag( '*', context ), function ( i, v ) {
                if ( ( ' ' + v.className + ' ' )
                            .indexOf( ' ' + className + ' ' ) != -1 ) {
                    results.push( v );
                }
            } );
        }
        return results;
    };
    
    
    // 对each方法的封装
    var each = function ( arr, fn ) {
        for ( var i = 0; i < arr.length; i++ ) {
            if ( fn.call( arr[ i ], i, arr[ i ] ) === false ) {
                break;
            }
        }
    };
            
    // 通用的get方法
    var get = function ( selector, context, results ) {
        results = results || [];
        var rquickExpr = /^(?:#([w-]+)|.([w-]+)|([w]+)|(*))$/,
            m = rquickExpr.exec( selector );
        
        if ( m ) {    
            if ( m[ 1 ] ) {
                results = getId( m[ 1 ], results );
            } else if ( m[ 2 ] ) {
                results = getClass( m[ 2 ], context, results );
            } else if ( m[ 3 ] ) {
                results = getTag( m[ 3 ], context, results );
            } else if ( m[ 4 ] ) {
                results = getTag( m[ 4 ], context, results );
            }
            
        }
    View Code

    验证以上封装的方法,html如下(为了使用方便,以下封装的js都单独放在common.js文件中,在html中须引入使用)

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title></title>
            <style type="text/css">
                .rect {
                     400px;
                    height: 50px;
                    margin: 10px 0;
                }
                .c  {  border: 1px dashed red; }
                .c1 { border: 1px dashed green; }
                .c2 { border: 1px dashed blue; }
            </style>
            <script src="common.js"></script>//把上面的函数单独放在一个js文件中,在html中引入
        </head>
        <body>
            <div class="c">
                <div class="c1 rect"></div>
                <div class="c2 rect"></div>
                <div class="c1 rect"></div>
                <div class="c2 rect"></div>
            </div>
            <hr />
            <div>
                <div class="c1 rect"></div>
                <div class="c2 rect"></div>
                <div class="c1 rect"></div>
                <div class="c2 rect"></div>
            </div>
        </body>
        <script type="text/javascript">
            get( '.c1', get( '.c' )[ 0 ] )[ 1]
                .style.backgroundColor = 'lightgreen';
            
        </script>
    </html>
    View Code

    2、问题描述:假设get方法中传入的context是一个DOM数组
    思路:首先想到需要遍历数组,那么问题来了,如何判断是否为DOM数组,如果不是数组怎么办,还有在哪一个方法中遍历呢

    // 注释: 对基本DOM数组方法的封装
    var getTag = function ( tag, context, results ) {
        results = results || [];
        results.push.apply( results, context.getElementsByTagName( tag ) );
        return results;
    };
    
    var getId = function ( id, results ) {
        results = results || [];
        results.push( document.getElementById( id ) );
        return results;
    };
    
    var getClass = function ( className, context, results ) {
        results = results || [];
    
        if ( document.getElementsByClassName ) {
            results.push.apply( results, context.getElementsByClassName( className ) );
        } else {
            each( getTag( '*', context ), function ( i, v ) {
                if ( ( ' ' + v.className + ' ' )
                            .indexOf( ' ' + className + ' ' ) != -1 ) {
                    results.push( v );
                }
            } );
        }
        return results;
    };
    
    
    // 对each方法的封装
    var each = function ( arr, fn ) {
        for ( var i = 0; i < arr.length; i++ ) {
            if ( fn.call( arr[ i ], i, arr[ i ] ) === false ) {
                break;
            }
        }
    };
            
    
    // 通用的方法
    var get = function ( selector, context, results ) {
        results = results || [];
        context = context || document;
        //                     1          2        3       4
        var rquickExpr = /^(?:#([w-]+)|.([w-]+)|([w]+)|(*))$/,
            m = rquickExpr.exec( selector );
        
        if ( m ) {        
            //此处判断context是否为数组,如果不是数组让其成为数组
            if ( context.nodeType ) {
                context = [ context ];
            }
            each( context, function ( i, v ) {
                if ( m[ 1 ] ) {
                    results = getId( m[ 1 ], results );
                } else if ( m[ 2 ] ) {
                    results = getClass( m[ 2 ], this, results );//this可以替代v
                } else if ( m[ 3 ] ) {
                    results = getTag( m[ 3 ], this, results );
                } else if ( m[ 4 ] ) {
                    results = getTag( m[ 4 ], this, results );
                }
            } );
        }
        
        return results;
    };
    View Code

    验证以上封装的方法,html如下

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title></title>
            <style type="text/css">
                .rect {
                     400px;
                    height: 50px;
                    margin: 10px 0;
                }
                .c  {  border: 1px dashed red; }
                .c1 { border: 1px dashed green; }
                .c2 { border: 1px dashed blue; }
            </style>
            <script src="common.js"></script>
        </head>
        <body>
            <div class="c">
                <div class="c1 rect"></div>
                <div class="c2 rect"></div>
                <div class="c1 rect"></div>
                <div class="c2 rect"></div>
            </div>
            <hr />
            <div class="c">
                <div class="c1 rect"></div>
                <div class="c2 rect"></div>
                <div class="c1 rect"></div>
                <div class="c2 rect"></div>
            </div>
        </body>
        <script type="text/javascript">
            var l = get( '.c' );
            each( get( '.c1', l ), function () { 
                this.style.backgroundColor = 'lightblue';
            } );
        </script>
    </html>
    View Code

    3、问题描述:假设get方法中传入的context是一个选择器字符串,也就是在页面中找到一个节点,然后在其后代再找出符合要求的节点
    思路:此时传入context是一个选择器字符串,判断其是否为字符串,现在假设先把这个字符串找出来,然后再通过each方法找出其后代的元素

    var myPush = function( target, els ) {
        var j = target.length,
            i = 0;
        // Can't trust NodeList.length
        while ( (target[j++] = els[i++]) ) {}
        target.length = j - 1;
    };
    
    
    // 注释: 对基本方法的封装
    var getTag = function ( tag, context, results ) {
        results = results || [];
        //此处也无须用context=context||[]
        try {
            results.push.apply( results, context.getElementsByTagName( tag ) );//ie8及以下版本不支持传入伪数组
        } catch ( e ) {
            myPush( results, context.getElementsByTagName( tag ) );//对ie8及以下版本的支持
        }
        
        return results;
    };
    
    var getId = function ( id, results ) {
        results = results || [];
        results.push( document.getElementById( id ) );
        return results;
    };
    
    var getClass = function ( className, context, results ) {
        results = results || [];
    
        if ( document.getElementsByClassName ) {
            results.push.apply( results, context.getElementsByClassName( className ) );
        } else {
            each( getTag( '*', context ), function ( i, v ) {
                if ( ( ' ' + v.className + ' ' )
                            .indexOf( ' ' + className + ' ' ) != -1 ) {
                    results.push( v );
                }
            } );
        }
        return results;
    };
    
    
    // 对each方法的封装
    var each = function ( arr, fn ) {
        for ( var i = 0; i < arr.length; i++ ) {
            if ( fn.call( arr[ i ], i, arr[ i ] ) === false ) {
                break;
            }
        }
    };
            
    
    // 通用的get方法
    var get = function ( selector, context, results ) {
        results = results || [];
        context = context || document;
        var rquickExpr = /^(?:#([w-]+)|.([w-]+)|([w]+)|(*))$/,
            m = rquickExpr.exec( selector );
        
        if ( m ) {
            if ( context.nodeType ) {
                context = [ context ];
            }
            //此时对context判断是否为字符串,如果是假设已经找出context
            if ( typeof context == 'string' ) {
                context = get( context );
            }
            each( context, function ( i, v ) {
                if ( m[ 1 ] ) {
                    results = getId( m[ 1 ], results );
                } else if ( m[ 2 ] ) {
                    results = getClass( m[ 2 ], this, results );//此处可以用this,也可以用v
                } else if ( m[ 3 ] ) {
                    results = getTag( m[ 3 ], this, results );
                } else if ( m[ 4 ] ) {
                    results = getTag( m[ 4 ], this, results );
                }
            } );
        }
        
        return results;
    };
    View Code

    验证以上封装的方法,html如下

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title></title>
            <style type="text/css">
                .rect {
                     400px;
                    height: 50px;
                    margin: 10px 0;
                }
                .c {
                    border: 1px dashed red;
                }
                .c1 { border: 1px dashed green; }
                .c2 { border: 1px dashed blue; }
            </style>
            
            <script src="common.js"></script>
        </head>
        <body>
            <div class="c">
                <div class="c1 rect"></div>
                <div class="c2 rect"></div>
                <div class="c1 rect"></div>
                <div class="c2 rect"></div>
            </div>
            <hr />
            <div>
                <div class="c1 rect"></div>
                <div class="c2 rect"></div>
            </div>
            <hr />
            <div class="c">
                <div class="c1 rect"></div>
            </div>
        </body>
        <script type="text/javascript">
            // 在页面中找到所有的 .c 的节点, 然后在 .c 的后代元素中
            // 找符合 .c1 的节点, 并返回
            each( get( '.c1', '.c' ), function () { 
                this.style.backgroundColor = 'skyblue';
            } );
        </script>
    </html>
    View Code


    4、问题描述:假设get方法中传入的context是多个选择器字符串,在这处理的是组合选择器

    思路: 拿到多个选择器的字符串, 首先需要处理的是逗号,将其分解成几个简单的部分, 然后再逐一处理,每一个子选择器, 都是按照从左往右的形式去过滤,先处理一个选择器, 得到的结果再被后面的选择器进行处理

    var myPush = function( target, els ) {
        var j = target.length,
            i = 0;
        // Can't trust NodeList.length
        while ( (target[j++] = els[i++]) ) {}
        target.length = j - 1;
    };
    
    
    // 注释: 对基本方法的封装
    var getTag = function ( tag, context, results ) {
        results = results || [];
        try {
            results.push.apply( results, context.getElementsByTagName( tag ) );
        } catch ( e ) {
            myPush( results, context.getElementsByTagName( tag ) );
        }
        
        return results;
    };
    
    var getId = function ( id, results ) {
        results = results || [];
        results.push( document.getElementById( id ) );
        return results;
    };
    
    var getClass = function ( className, context, results ) {
        results = results || [];
    
        if ( document.getElementsByClassName ) {
            results.push.apply( results, context.getElementsByClassName( className ) );
        } else {
            each( getTag( '*', context ), function ( i, v ) {
                if ( ( ' ' + v.className + ' ' )
                            .indexOf( ' ' + className + ' ' ) != -1 ) {
                    results.push( v );
                }
            } );
        }
        return results;
    };
    
    
    // 对each方法的封装
    var each = function ( arr, fn ) {
        for ( var i = 0; i < arr.length; i++ ) {
            if ( fn.call( arr[ i ], i, arr[ i ] ) === false ) {
                break;
            }
        }
    };
            
    //对myTrim方法的封装,去空格
    var myTrim = function ( str ) {
                    if ( String.prototype.trim ) {
                        return str.trim();
                    } else {
                        return str.replace( /^s+|s+$/g, '' );
                    }
                };
                
    // 通用的get方法
    var get = function ( selector, context, results ) {
        results = results || [];
        context = context || document;
        //                     1          2        3       4
        var rquickExpr = /^(?:#([w-]+)|.([w-]+)|([w]+)|(*))$/,
            m = rquickExpr.exec( selector );
        
        if ( m ) {
            if ( context.nodeType ) {
                context = [ context ];
            }
            // 如果 context 是一个 dom 数组就没有问题了
            // 但是 context 是一个选择器字符串. 有可能是 '.c'
            // 
            if ( typeof context == 'string' ) {
                context = get( context );
            }
            each( context, function ( i, v ) {
                if ( m[ 1 ] ) {
                    results = getId( m[ 1 ], results );
                } else if ( m[ 2 ] ) {
                    results = getClass( m[ 2 ], v, results );
                } else if ( m[ 3 ] ) {
                    results = getTag( m[ 3 ], this, results );
                } else if ( m[ 4 ] ) {
                    results = getTag( m[ 4 ], this, results );
                }
            } );
        }
        
        return results;
    };
    
    var select = function ( selector, context, results ) {
                    results = results || [];
                    // 首先处理逗号
                    var newSelectors = selector.split( ',' );
                    // 细节: 一般不考虑两端的空格
                    each( newSelectors, function ( i, v ) {
                        results.push.apply( results, get( myTrim( v ), context ) );    
                    } );
                    //此处我们可以用for in方法进行分解
                    /*for(var k in newSelectors){
                        var v = newSelectors[k];
                            v = myTrim(v)//v.trim();
                        var list = get(v,context);
                        results.push.apply(results,list);    
                        
                    }*/    
                    return results;
                };
    View Code

    验证以上封装的方法,html如下

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title></title>
            <style type="text/css">
                .rect {
                     400px;
                    height: 50px;
                    margin: 10px 0;
                }
                .c1 {
                    border: 1px dashed red;
                }
                .c2 { border: 1px dashed green; }
                .c3 { border: 1px dashed blue; }
            </style>
            <script src="common.js"></script>
    
        </head>
        <body>
            <div class="c">
                <div class="c1 rect"></div>
                <div class="c2 rect"></div>
                <div class="c3 rect"></div>
                <div class="c2 rect"></div>
            </div>
            <hr />
            <div>
                <div class="c1 rect"></div>
                <div class="c3 rect"></div>
            </div>
            <hr />
            <div class="c">
                <div class="c1 rect"></div>
            </div>
        </body>
        <script>
            var list = select( '.c1, .c2' );
            each( list, function () {
                this.style.backgroundColor = 'skyblue';
            });
            
        </script>
    </html>
    View Code

    5、问题描述:在这我们传入的是后代选择器字符串

    思路:假设list = get('.c  .c1',context),即在context下找出.c,然后再在.c下找出.c1

    等价于:list = get('.c ',context);  list = get('.c1',list) 

    var myPush = function( target, els ) {
        var j = target.length,
            i = 0;
        // Can't trust NodeList.length
        while ( (target[j++] = els[i++]) ) {}
        target.length = j - 1;
    };
    
    
    // 注释: 对基本方法的封装
    var getTag = function ( tag, context, results ) {
        results = results || [];
        try {
            results.push.apply( results, context.getElementsByTagName( tag ) );
        } catch ( e ) {
            myPush( results, context.getElementsByTagName( tag ) );
        }
        
        return results;
    };
    
    var getId = function ( id, results ) {
        results = results || [];
        results.push( document.getElementById( id ) );
        return results;
    };
    
    var getClass = function ( className, context, results ) {
        results = results || [];
    
        if ( document.getElementsByClassName ) {
            results.push.apply( results, context.getElementsByClassName( className ) );
        } else {
            each( getTag( '*', context ), function ( i, v ) {
                if ( ( ' ' + v.className + ' ' )
                            .indexOf( ' ' + className + ' ' ) != -1 ) {
                    results.push( v );
                }
            } );
        }
        return results;
    };
    
    
    // 对each方法的封装
    var each = function ( arr, fn ) {
        for ( var i = 0; i < arr.length; i++ ) {
            if ( fn.call( arr[ i ], i, arr[ i ] ) === false ) {
                break;
            }
        }
    };
            
    //对myTrim方法的封装,去空格
    var myTrim = function ( str ) {
                    if ( String.prototype.trim ) {
                        return str.trim();
                    } else {
                        return str.replace( /^s+|s+$/g, '' );
                    }
                };
                
    // 通用的get方法
    var get = function ( selector, context, results ) {
        results = results || [];
        context = context || document;
        //                     1          2        3       4
        var rquickExpr = /^(?:#([w-]+)|.([w-]+)|([w]+)|(*))$/,
            m = rquickExpr.exec( selector );
        
        if ( m ) {
            if ( context.nodeType ) {
                context = [ context ];
            }
            // 如果 context 是一个 dom 数组就没有问题了
            // 但是 context 是一个选择器字符串. 有可能是 '.c'
            // 
            if ( typeof context == 'string' ) {
                context = get( context );
            }
            each( context, function ( i, v ) {
                if ( m[ 1 ] ) {
                    results = getId( m[ 1 ], results );
                } else if ( m[ 2 ] ) {
                    results = getClass( m[ 2 ], v, results );
                } else if ( m[ 3 ] ) {
                    results = getTag( m[ 3 ], this, results );
                } else if ( m[ 4 ] ) {
                    results = getTag( m[ 4 ], this, results );
                }
            } );
        }
        
        return results;
    };
    
    var select = function ( selector, context, results ) {
                    results = results || [];
                    // 首先处理逗号
                    var newSelectors = selector.split( ',' );
                    // 细节: 一般不考虑两端的空格
                    each( newSelectors, function ( i, v ) {
                        
                        var list = v.split(' ');
                        var cont = context;
                        for(var i = 0;i <list.length;i++){
                            //如果list[i]是空字符串,会生成一个新数组,则需要进行如下判断
                            if(list[i] === '') continue;
                            cont = get(list[i],cont);
                        }
                        results.push.apply( results, cont );    
                    } );
                    
                    return results;
                };
    View Code

    验证以上封装的方法,html如下

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title></title>
            <style type="text/css">
                .rect {
                     400px;
                    height: 50px;
                    margin: 10px 0;
                }
                .c1 {
                    border: 1px dashed red;
                }
                .c2 { border: 1px dashed green; }
                .c3 { border: 1px dashed blue; }
            </style>
            <script src="common.js"></script>
    
        </head>
        <body>
            <div class="c">
                <div class="c1 rect"></div>
                <div class="c2 rect"></div>
                <div class="c3 rect"><p>123</p></div>
                <div class="c2 rect"></div>
            </div>
            <hr />
            <div>
                <div class="c1 rect"></div>
                <div class="c3 rect"></div>
            </div>
            <hr />
            <div class="c">
                <div class="c1 rect"></div>
            </div>
        </body>
        <script>
            var list = select( '.c .c2' );
            each( list, function () {
                this.style.backgroundColor = 'skyblue';
            });
            
        </script>
    </html>
    View Code

    未完待续

  • 相关阅读:
    Delphi TStringList的用法
    Android Studio使用教程(一)
    如何在win7下安装和配置Android Studio
    python基础字符串单引号双引号和三引号
    同步和互斥
    posix多线程有感线程高级编程(条件变量)
    VMware网络配置详解
    posix多线程有感POSIX 线程间的内存可视性
    进程及相关API
    POSIX线程属性
  • 原文地址:https://www.cnblogs.com/goweb/p/5380877.html
Copyright © 2020-2023  润新知