在网上下了一个类似于jQuery的小框架,分析源码,看看怎么写框架。

选择器Select

//用沙箱闭包其整个代码,只有itcast和I暴漏在全局作用域
(function( window , undefined){
    //Itcast函数,参数:selector。返回值一个Itcast对象,功能:new Itcast。prototype。init()
    function Itcast(selector){
        return new Itcast.prototype.init();
    }
    // Itcast的原型属性用替换重新定义
    Itcast.prototype = {
        constructor: Itcast,
        type: "Itcast",
        length: 0,
        //constructor指向构造函数Itcast,type记录对象类型“Itcast”,length:变成伪数组
        // init函数 功能:Itcast对象的真正的构造函数,根据参数类型,进行不同的处理: 参数:selector。
        // 返回值:只要在适当的位置返回即可,构造函数不需要返回值,但是为了提醒这里是为了创建对象,所以写成return this
        //因为init是构造函数,this就是指创建出来的这个对象,现在要把获取到的dom对象全部追加到this中来,再通过Itcast返回
        // 。因为Itcast和init是用的同一个原型,所以认为此处创建出来的就是Itcast对象
        init:function(selector){
            var push = [].push;
            if( typeof selector == "string"){
                // 如果selector是html字符串,用parseHtml将其转成DOM伪数组,再转成this(Itcast伪数组)
                if( selector.charAt(0) == "<"){
                    push.apply(this , parseHTML(selector));
                }else{
                    // 如果selector是选择器。用Select函数,
                    push.apply(this , Select(selector));
                }

            }
            //   如果是function ,近似于onload
            if( typeof selector == "function"){

            }
            //  如果是dom,追加到this(Itcast伪数组)中
            if( selector.nodeType ){

            }
            // 如果是Itcast对象,追加到新的Itcast对象中返回
            if( selector.type = "Itcast" ){

            }
        }
    }

    //让init的原型属性指向Itcast。prototype。即有init创建出来的对象也就是Itcast对象了
    Itcast.prototype.init.prototype = Itcast.fn = Itcast.prototype;
    //设定Itcast的扩展方式,Itcast。extend(静态成员扩展) 。 Itcast.prototype.extend(动态成员扩展)
    // .函数参数: 对象option。 返回值: 无, 功能:将option中的属性或方法依次添加给Itcast或Itcast.fn
    Itcast.fn.extend = Itcast.extend = function(option){
        for( var k in option){
            this[ k ]  = option[ k ];
        }
    }
    //模块化,功能化。(构造函数的补充)
        //扩充静态成员
            //选择器Select(闭包,仅将Select暴漏在外面)参数:无,返回值Select函数。
            // 功能:再沙箱中将Select函数定义好,
    var Select = (function(){
        //数据初始化:
        //将某些浏览器是否支持a方法用对象support储存起来以免每一次动用函数的时候都要进行查找
        // 是否提供可以看函数体是否包含 [native code]即可;,正则表达式的变量以r开头
        var rnative = /\[native code\]/,
            push = [].push ,
            i,
            div = document.createElement("div");
        var support = {
            qsa: rnative.test(document.querySelectorAll),
            getByClass : rnative.test( document.getElementsByClassName),
            getByClass2: rnative.test(div.getElementsByClassName),
            trim: rnative.test(String.prototype.trim),
            indexOf: rnative.test(Array.prototype.indexOf),
        }
        // 要用的函数提前准备好
        // push,push没有兼容性问题但是push.apply再IE低版本,不能展开伪数组,会报错
        // ,因此用try{}catch的方法兼容
        try{
            push.apply([],document.getElementsByTagName("*"));
        }catch(e){
            //z自定义push.apply的函数,参数数组a,伪数组b, 返回值 数组a,
            // 功能:将b中的内容添加到 a当中;
            var  push = {
                apply : function( a , b){
                    for( var i =0 ; i< b.length ; i++ ){
                        a[ a.length++ ] = b[ i ];
                    }
                    return a;
                }
            }
        }
        //trim 参数:字符串 ,返回值:首位去除空白的I字符串。功能:将字符串的两端的空白去出,并返回
        function trim( str ){
            if( support.trim ){
                return str.trim();
            }else{
                var rtrim = /^\s+|\s+$/;
                return  str.replace( rtrim , "");
            }
        }
        // indexOf,参数数组arr,a要查找项,返回值:a的索引值,如果没有返回-1
        //indexOf 还需要一个参数, 就是 查找的开始位置
        function indexOf( arr , a,startIndex){
            startIndex = startIndex || 0;
            if(support.indexOf){
                return arr.indexOf(a , startIndex);
            }
            for(var i = startIndex; i< arr.length ;i++){
                if( arr[ i ] === a){
                    return i;
                }
            }
            return -1;
        }
        //unique函数,参数:数组 ,返回值:去重之后的数组,功能: 将穿进来的数组中的重复项去除
        function unique( arr ){
            var array = [];
            for( var i=0 ; i< arr.length ;i++){
                if(indexOf( array ,arr[ i ]) == -1){
                    array.push( arr[i]);
                }
            }
            return array;
        }
        //核心函数Select:参数:selector选择器, 要被添加元素的数组或伪数组results, 返回值results
        //功能: 将selector对应的DOM对象,追加到results中输出
        function Select(selector ,results){
            results = results || [];
            if( typeof selector !== "string"){
                return ;
            }
            //如果浏览器支持querySelectorAll就用,如果不支持,就自己定义一个select2
            if( support.qsa ){
                return document.querySelectorAll( selector );
            }else {
                return select2( selector);
            }
        }
        // select2,参数:selector选择器,返回值dom对象,
        function select2( selector ,results){
            // 功能:看选择器是不是并集选择器,将selector用trim函数去掉首尾的空白()
            results = results || [];
            // ,再用split函数切割成数组,
            var arr = selector.split(",");
            for( i = 0 ; i < arr.length ; i++){
            // 再用select3函数进行处理,将切割好的字符串用trim方法取出前后空白
             select3( trim(arr[ i ]) , results);
            }
            return unique(results);
        }
        function select3 ( selector , results){
            results = results || [];
            //select3函数:参数select ,返回值dom对象。功能:判断选择器是“*”还是id,还是类,还是标签
            var first = selector.charAt(0);
            //注意如果是类选择器,document.getElementsByClassName有浏览器兼容性问题。
            //区分好后,调用相应的函数进行处理
           //此处屏蔽掉后代选择器的影响,此时如果selector经过了首尾去空格后还有空格,说明是后代选择器
            if( selector.slice(" ").length == 1){
                if(selector == "*"){
                    /*
                     results = document.getElementsByTagName("*");
                     return results;
                     ,如果results原来就有内容,此处把results中的内容全部覆盖了所以不行,
                     要将选择器对应的dom元素挨个追加到results中
                     */
                }else if( first == "#"){
                    return id(selector.slice(1) , results);
                }else if( first == "."){
                    //类
                    return c(selector.slice(1),results);
                }else {
                    //标签
                    return t(selector , results)
                }
            }else{
                //如果是后代选择器,此处咱不处理,抛出一个bug,提示升级浏览器
                throw new Error("您的浏览器版本过低,请升级浏览器")
            }
        }

        //参数:选择器selector 被追加元素的数组。 返回值: results
        //功能: 将selector对应的元素挨个追加到results中并输出,
        function id( selector ,results ){
            results = results || [];
            push.apply(results , document.getElementById(selector));
            return results;
        }
       // 标签
        function t( selector , results){
            results = results || [];
            push.apply( results , document.getElementsByTagName( selector));
            return results;
        }
        //类,getElementsByClassName有浏览器兼容行问题,
        function c( selector , results ){
            results = results || [];
            push.apply( results , getByClass( selector , document));
            return results;
        }

        //兼容类选择器,参数:类名className ,查找返回node,返回值:返回查找到的dom元素数组
        //功能: 用className属性查找node中的符合条件的dom对象,并返回对象数组
        function getByClass(className , node){
            node = node || document;
            //如果浏览器支持
            if( node == document && support.getByClass || node.nodeType && support.getByClass2){
                return node.getElementsByClassName(className);
            }else{
                //如果浏览器不支持
                //获取所有的标签,遍历
                var list = node.getElementsByTagName("*"),
                    arr = [],
                    tempClassName;
                for( var i = 0 ; i< list.length ;i++){
                    tempClassName = list[ i ];
                    if( !tempClassName ){
                        continue;
                    }    //再class属性存在的情况下
                    //用slice(“ ”)分割
                    //判断是否与className相同
                    //如果相同追加到results中
                    if(indexOf(tempClassName.slice(" "),className) !== -1){
                        arr.push(tempClassName);
                    }
                }
                return arr;

            }

        }

        return Select;
    })();



            // 解析html字符串parseHTML
                //在解析过程中,需要在内存中创建一个node,为了不暴漏在外面使用沙箱(自调自用的函数,返回该数组)
                //参数:selector,(html字符串),返回值存储dom的数组,功能: 将html字符串转化成dom对象储存在数组中
    Itcast.parseHTML =(function (){
        var node = document.createElement("div");
        var arr = [];
        function parseHTML(selector){
            node.innerHTML = selector;
            arr.push.apply(arr , node.childNodes);
            return arr;
        }
        return parseHTML;
    })();

    //扩充实例成员
  Itcast.fn.extend({
      appendTo: function ( parent , child ){
          parent.appendChild( child );
      }
  })



    //将Itcast挂在window上
    window.Itcast = window.I = Itcast;
})(window);

  

posted on 2016-08-23 00:15  下辈子当座桥-李飞  阅读(387)  评论(0编辑  收藏  举报