zoukankan      html  css  js  c++  java
  • JavaScript框架设计(四) 字符串选择器(选择器模块结束)

    JavaScript框架设计(四) 字符串选择器(选择器模块结束)

    经过前面JavaScript框架设计(三) push兼容性和选择器上下文的铺垫,实现了在某一元素下寻找,现在终于进入了字符串选择器

    首先,我们解决组合选择器,因为在一个选择器字符串中,它的优先级是最低的.


    组合选择器

    由于组合选择器是一个包含逗号的字符串,我们可以将其用逗号分隔开

    下面看代码

    01.html

    var HPawn = function (selector) {
        var res = [];
        var list = selector.split(',');// 先将选择器字符串用逗号分隔开
        each(list, function (v) {
            get(myTrim(v), document, res);
        })
        return res;
    }
    

    在这里,我终于要引出我的关键对象 HPawn了,这个会在后面的面向对象封装中见到.

    由于 String.prototype.trim() 在ie8 里面是不支持的,所以自己也要实现一个myTrim.

    var myTrim = function (str) {
        // 如果本身有自己的get方法就调用,如果没有,就使用自己的myTrim方法.
        if (String.prototype.trim) {
            str = str.trim();
        } else {
            str.replace(/^s|s$/, "");
        }
        return str;
    }
    

    str.replace(/^s|s$/, ""); 这里 是一个简单的正则替换.

    下面是测试代码:

    01.html

        <style>
            .c1,.c2,.c3,#dv{
                border: 1px solid lightblue;
                 300px;
                height: 60px;
                margin-bottom: 20px;
            }
        </style>
    </head>
    
    <body>
        <!--实现组合选择器-->
        <div class="c1">
            <div id="dv"></div>
        </div>
        <div class="c2"></div>
        <div class="c3"></div>
    </body>
    <script src="common.js"></script>
    
    onload = function () {
    	each(HPawn('#dv,.c2,.c3,'), function (v) {
    		this.style.backgroundColor = 'red';
    	})
    }
    
    

    看效果:


    后代选择器

    好了,上面已经解决了组合选择器的问题,下面开始后代选择器,选择器模块也在后代选择器之后结束,.

    对于后代选择器,类似"div p span .c",我们首先想到的就是使用空格" "分割,得到每一个部分,从每一个部分中找到下面的部分,这就是一个递归的过程.

    由于以空格分隔是比较特殊的,所以我们先介绍String.prototype.split() 这个方法.

    如图:

    在对字符串"1 2 3"(注意,2和3之间是两个空格),我们得到了四个元素,'1', '2'. '', '3',包含一个空字符串.

    为什么会这样呢?

    我们分析split的原理.

    首先,游标从第一个字符开始,发现不是' ',就会到第二个字符' ',发现是' ',砍一刀,将前面的东西push到结果中.再继续走到达'2',发现不是' ',继续向前,到达' ',砍一刀,将前面的push到结果中,再向前走,发现还是' ',再砍一刀,将前面的字符串,也就是空字符串push到结果中...

    好了,既然这样,那我们用' '来分割字符串的时候,很有可能会包含空字符串,我们必须做个判断.

    看下面的递推式

    var str = "l1,l2,l3,l4";

    res = getChild(context,l1,0);

    res = getChild(res,l2,1);

    res = getChild(res,l3,2);

    res = getChild(res,l4,3);

    详细的理论过程就是上面这样,可以看到,后代选择器有几组,那么就会递归几次.

    看下面的代码:

    var getChild = function (parent, index) {
        // 如果已经超出了范围,就返回父元素数组
        if (index >= selectors.length) {
        	return parent;
        }
        // 如果父元素没有找到,那么就直接返回空数组
        if (!parent || parent.length == 0) {
        	return [];
        }
        // 如果选择器为空字符串,那么就直接越过一级查找
        if (!selectors[index]) {
            index += 2;
            return getChild(parent, index);
        }
        var res = get(selectors[index], parent);
        return index == (selectors.length - 1)
            ? res :
            getChild(res, ++index);
    }
    
    
    

    这里接受两个参数,第一个为父元素dom数组,第二个表示第几级,第一次调用的时候,index就是0.

    下面是一个for循环版本,很直观的解释了后代选择器的选择算法.

    	var parent = context;
        for (var i = 0; i < selectors.length; i++) {
            if (!selectors[i]) {
            	continue;
    		}
    		// 如果parent为空,就直接不再向后判断
    		if(!arent){
                return [];
    		}
    		parent = get(selectors[i],parent);	
    	}
    

    比如说选择器 'div p span',使用空格分开后,得到的就是字符串数组,然后从第一个字符串查找元素下一级元素,一直查找到末尾,然后返回.

    现在我们把上面的代码整合

    02.js

    /// <reference path="common.js" />
    var myTrim = function (str) {
        // 如果本身有自己的get方法就调用,如果没有,就使用自己的trim方法.
        if (String.prototype.trim) {
            str = str.trim();
        } else {
            str.replace(/^s|s$/, "");
        }
        return str;
    }
    
    // 在组合选择器的基础上实现后代选择器
    var HPawn = function (selector, context, result) {
        var result = result || [];
        context = context || document;
        var list = selector.split(',');// 先将选择器字符串用逗号分隔开
        // 首先,应当对每一个被分开的元素进行split(' ') 
        each(list, function (v) {
            v = myTrim(v);
            var selectors = v.split(' ');
            // 在这里,一个递归
            var getChild = function (parent, index) {
                // 如果已经超出了范围,就返回父元素数组
                if (index >= selectors.length) {
                    return parent;
                }
                // 如果父元素没有找到,那么就直接返回空数组
                if (!parent || parent.length == 0) {
                    return [];
                }
                // 如果选择器为空字符串,那么就直接越过一级查找
                if (!selectors[index]) {
                    index += 2;
                    return getChild(parent, index);
                }
                var res = get(selectors[index], parent);
                return index == (selectors.length - 1)
                    ? res :
                    getChild(res, ++index);
            }
    
            each(selectors, function (v) {
                result.push.apply(result, getChild(context, 0));
            })
        });
        return result;
    }
    
    

    好了,后代选择器已经完成了,下面写个demo.

    02.htm

        <style>
            div {
                border: 1px solid green;
               
                padding: 20px;
                box-sizing: border-box;
                margin-bottom: 30px;
            }
            
            .c {
                height:300px;
                 500px;
            }
            
            .c1,
            .c2,
            .c4 {
                height: 80px;
                 400px;
            }
            
            .c3,
            .c5 {
                height: 40px;
                 200px;
    
            }
        </style>
    
        <div class="c">
            <div class="c1">
                <div class="c3"></div>
            </div>
            <div class="c2"></div>
        </div>
    <hr/>
        <div class="c4">
            <div class="c5"></div>
        </div>
    </head>
    
    <body>
        <script src="common.js"></script>
        <script src="02.js"></script>
    
    
    </body>
    

    02.js

    // 这个代码实在是太简洁了,太棒了

    onload = function () {
        each(HPawn('.c4 .c5,.c .c1 .c3'), function () {
            this.style.backgroundColor = 'orange';
        })
    
    }
    

    下面是效果

    看起来已经大功告成了.


    好了,选择器模块我们已经实现了组合选择器和后代选择器.

    但是jQuery还有很多,比如 父子选择器,兄弟选择器,下一个,上一个,过滤器. 这些以后还需要再细心钻研啊.

    好了,现在我们写一个简单的循环将这两个选择器做一个简化

    03.js

    var Hpawn = function (selector) {
        var result = []
        var selectors = selector.split(',');
        for (var i = 0, length = selectors.length; i < length; i++) {
            var singleSelectors = selectors[i].split(' ');
            var parent = document;
            for (var j = 0; j < singleSelectors.length; i++) {
                parent = get(singleSelectors[j], parent);
            }
    
            result.push.apply(result, parent);
        }
        return res;
    }
    

    上面的代码需要用到common.js里面的东西,也就是通用的get方法.

    看起来,组合选择器和父子选择器就是这么简单,几句代码就搞定了,确实是,逻辑比较简单.

    但是,它只能用作理解,太不严谨了.

    好了,选择器模块已经结束.

    下面,我会JavaScript框架设计(五)开始一个新的模块:Dom操作模块

    最后特别感谢恩师蒋坤老师(jk)对我的知识学习和人生引导的极大帮助,非常感谢他.

  • 相关阅读:
    document 对象
    AdodbStream的方法和属性
    WEB开发者版本
    ATI HD2400
    驱蚊植物
    PHP5+UTF8多文件上传类
    nVIDIA_driver
    ati
    Zend_Http_Client setFileUpload
    Sqlserver2005 数据类型
  • 原文地址:https://www.cnblogs.com/likeFlyingFish/p/5738682.html
Copyright © 2011-2022 走看看