美文网首页
2017-04-17 jQuery 原理

2017-04-17 jQuery 原理

作者: GodlinE | 来源:发表于2017-04-17 18:17 被阅读0次

    jQuery 的内部实现

    • 课程目标

    • 需要掌握
      了解常用方法的使用
      掌握常用方法的底层实现逻辑
      学会根据一个目标需求,来根据自己的思想编写出大致实现
      了解一些编写框架的技巧,比如为什么用闭包,为什么传递 window 参数
      了解一些机制,比如插件机制,如何扩展一些方法或者属性
      要求掌握面向对象的思想去解决问题,熟练了解原型, this 指针等概念

    • 整体是一个执行的闭包
      这样写的主要目的是为了防止内部一些功能被污染

    • 传递 window 参数
      是为了方便亚索,以及提高检索效率

    • 内部接收 undefined
      是为了放置,外界修改 undefined 所代表的含义

    • 内部的参数,如何让外界可以访问
      可以通过给 window 对象,动态的增加属性,暴露给外界调用

    (function(){
            //1.定义构造函数
            var szjQuery = function(selector){
                    //内部 new 了一个对象返回给外界,让外界使用方便,没必要再创建
                    return new szjQuery.prototype.init(selector);
            }
            //2.修改函数的原型
            //以后,可以在这个位置扩展一些属性,或者方法
            //注意:这里有个比较重要的方法 init 方法,基本上所有的创建 jQuery 对象初始化的逻辑,都是在这个函数里面进行处理的
            szjQuery.prototype = {
                    szjQuery:'1.1.0',
                    selector:'',
                    length:0,
                    constructor:szjQuery,
                    init:function(){
                            //this.length = 0;
                            //在这里处理 selector 传进来的参数
                            //1.特殊字符 ‘’ null undefined NaN 0 false
                            if(!selector){
                                    return this;
                            } 
                            //2.判断是否是字符串
                            if($.isString(selector)){
                                    //2.1要不就是代码片段,去空格处理
                                    var result = $.trimString(selector);
                                    if($.isHTML(result)){
                                            var tag = document.createElement('div');
                                            tag.innerHTML = selector;
                                            var firstChildren = tag.children;
                                            //call  apply 作用重新控制 this 指向,此处可以使用遍历然后控制 this[i] = firstChildren[i] 来实现
                                            [].push.apply(this,firstChildren);
                                            return this;
                                    }
                                    //2.2要不就是选择器
                                    var tags = document.querySelectorAll(selector);
                                    [].push.apply(this,tags);
                                    return this;      
                            } 
                            //3.判定是否是伪数组/真数组
                            if($.isWindow(selector) && $.isLikeArray(selector)){
                                    [].push.apply(this,selector);
                                    return this;    
                            } 
                            //4.判断是否是一个函数
                            if($.isFunction(selector)){
                                    $.ready(selector);
                            } 
                            //其他
                            //DOM 基本对象 基本数据类型 1234
                            this[0] = selector;
                            this.length = 1;
                            return this;                    
                    }        
            };
            //3.创建一个快速批量创建静态方法/实例方法的方法
            //因为内部的 this ,是动态指向调用者的
            //所以,可以借助这个特性,来动态的给对象或者方法添加方法
            szjQuery.extend = szjQuery.prototype.extend = function(funDic){
                    for(var key in funDic){
                            this[key] = funDic[key];
                    }        
            }
            //4.重新修改 init 函数的原型指向,避免方法调用不到的问题
            //此处必须了解以下几点
            //4.1每个函数都有对应的原型对象
            //4.2通过什么构造函数,创建出来的实例对象,这个对象的 __proto__ 就指向该构造函数的原型对象
            //4.3当调用一个对象方法的时候,是根据 __proto__ 来进行查找方法的
            //4.4所以,当一个对象找不到方法,应该注意查看该对象的构造函数的
            //4.5注意,任何一个函数的原型,都可以修改
            szjQuery.prototype.init.prototype = szjQuery.prototype;
            //通过 window 对象,将内部对象暴露给外界
            //因为,基本上,所有的功能都是依附于 jQuery 对象存在的
            //所以,可以jQuery 对象给外界,然后其他的信息,会被间接的暴露出去
            window.szjQuery = window.$ = szjQuery;
            //6.扩展静态方法
            //工具类,判断类的是否是字符串,是否是对象等等
            szjQuery.extend({
                   //是否是字符串方法
                   'isString':function(){
                            return typeof str === 'string';
                    },
                    //可以压缩字符串的首尾空格
                    //此处注意兼容,以及正则表达式的使用
                    'trimString':function(str){
                            if(str.trim){
                                    return str.trim();
                            }
                            return str.replace(/^\s+|\s+$/g, '');
                    },
                    //判断是否是窗口过对象
                    'isWindow': function(w){
                            return window.window !== w;
                    },
                    //是否是伪数组
                    'isLikeArray':function(){
                            return (this.isObject(arr) && 'length' in arr && (arr.length - 1) in arr);
                    },    
                    //是否是对象
                    'isObject':function(obj){
                            return typeof obj === 'object';
                    },
                    //是否是代码片段
                    //注意空格的容错处理
                    'isHTML':function(html){
                            return html.charAt(0) === '<' && html.charAt(html.length - 1) === '>' &&html.length > 3
                    },
                    //是否是函数
                    'isFunction':function(fun){
                            return typeof fun === 'function';
                    },
                    //是否是 DOM 对象
                    'isDOM':function(dom){
                            if('nodeType' in dom){
                                    return true;
                            }
                            return false;
                    },
                    //入口函数的处理
                    //需要注意执行时机,以及执行次数
                    'ready':function(func){
                            if(!$.isFunction(func)){
                                    return;
                            }
                            //1.判断当前文档是否已经加载完毕
                            //直接执行
                            //document.readyState 可以兼容当前所有主流浏览器
                            var state = document.readyState;
                            if(state === 'complete'){
                                    func();
                                    return;
                            }
                            //2.如果没有加载完毕
                            //监听 DOM 树建立完成
                            // IE9+
                            if(document.addEventListener){
                                    document.addEventListener('DOMContentloaded',func);
                                    return;
                            }
                            // IE8
                            document.attachEvent('onreadystatechange',function(){
                                    var state = document.readyState;
                                    if(state === 'complete'){
                                            func();
                                    }
                            });
                    }
            });
    //扩展实例方法
    //数组相关的一些方法
    //比如转换称为数组,遍历,切割数组等等
    //此处需要掌握,数组操作的常用方法的内部实现
    szjQuery.prototype.extend({
            //将伪数组,转换成为真数组
            'toArray':function(){
                    var result = [].slice.call(this);
                    return result;
              //
                // begin = begin === undefined ? 0 : begin;
                // end = (end === undefined || end > this.length) ? this.length: end;
                //
                // var tmpArr = [];
                // for (var i = begin; i < end; i++) {
                //     tmpArr.push(this[i]);
                // }
                //
                // return tmpArr;
            },
            //7.2获取某个一个 DOM 元素
            //注意正负索引值的处理
            'get':function(index){
                    if(index === undefined){
                            return this.toArray();
                    }
                    index = index >=0?index:index + this.length;
                    return this[index];
                // if (index >= 0) {
                //     return this[index];
                // }
                // // -1 +
                // index = index + this.length;
                // return this[index];
            },
            //7.3获取指定的 DOM 元素,包装的 jQuery 对象
            //可以考虑,借助其他已经实现过的方法,进行处理
            //因为,内部的逻辑大致和 get 方法类似
            'eq':function(index){
                    if(index === undefined){
                            return $('');
                    }
                    return $(this.get(index));
            },
            //7.4获取第一个的 DOM 元素,包装的 jQuery 对象
            //可以考虑,借助其他已经实现国的方法,进行处理
            //因为,内部的逻辑,大致和 get 方法类似
            'first':function(){
                    return this.eq(0);
            },
            //7.5 获取最后一个的 DOM 元素,包装 jQuery 对象
            //可以考虑,借助其他已经实现的方法,进行处理
            //因为,内部的逻辑,大致和 get  方法类似
            'last':function(){
                    return this.eq(-1);
            },
            //[].splice 获取的是方法实现
            //7.6一定要注意,jQuery 对象里面的,这些方法的实现,其实和数组的这些方法实现一模一样
            //所以,此处,可以直接把数组对应方法的实现放在这里
            //这样,到时候,外界调用的时候,就会按照相同的操作数组的逻辑,来操作 jQuery 对象
            'splice':[].solice,
            'push':[].push,
            'sort':[].sort,
            'each':function(func){
                    $.each(this,func);
            },
            'reverse':function(){
                    var result = [];
                    for(var i = this.length - 1 ; i >= 0;i--){
                           result.push(this[i]);                     
                    }
                    return $(result);
            }
    });
    //8.静态方法
    //数组相关
    szjQuery.extend({
            //8.1 遍历数组,或者伪数组,或者对象
            //内部注意不同类型的处理
            //还有就是,此方法,支持对象方法,和静态方法
            //一般碰到这种情况,我们优先开发静态方法,然后再在实例方法中,调用静态方法实现即可
            'each':function(obj,func){
                    if($.isLikeArray(obj)){
                            for(var i = 0;i < obj.length;i++){
                                    //func(i,obj[i]);
                                    var isContinue = func.call(obj[i],i,obj[i]);
                                    //isContinue = isContinue !== undefined ? isContinue : true;
                                    if(isContinue === undefined){
                                            isContinue = true;
                                    }
                                    if(!isContinue){
                                            return;
                                    }
                            }
                            return;
                    }
                    //不是伪数组
                    if($.isObject(obj)){
                            for(var key in obj){
                                    //func(key,obj[key]);
                                    var isContinue = func.call(obj[key],key,obj[key]);
                                    isContinue = isContinue !== undefined ? isContinue:true;
                                    if(!isContinue){
                                            return;
                                    }
                            }
                    }
            },
            //8.2可以将一个字符串的空格,都给亚索,然后把里面的有效元素,存储到一个数组中
            //可以用来做一些格式化的操作
            'trimSpaceArrayWithStr':function(str){
                    var resultArray = [];
                    var temp = str.split(' ');
                    for(var i = 0 ; i < temp.length;i++){
                            var value = temp[i];
                            if(value.length > 0){
                                    resultArray.push(value);
                            }
                    }
                    return resultArray;
            }
    });
    //DOM 操作的相关方法
    //注意:如果想要仿照一个功能
    //先对这个功能进行充分的测试
    //报错参数 参数个数 参数类型 返回值等信息
    szjQuery.prototype.extend({
            //9.1 清空 DOM 对象里面的内容
            'empty':function(){
                    this.each(function(){
                            //index value  value
                            //this 就是每一个 DOM 对象
                            this.innerHTML = '';
                    });
                    return this;
            },
            //9.2 删除指定的 DOM 对象
            'remove':function(){
                    this.each(function(){
                            //this 是每一个 DOM 对象
                            this.parentNode.removeChild(this);
                    });
                    return this;
            },
            //9.3获取指定元素的 html 内容
            'html':function(content){
                    if(content === undefined){
                            return this.get(0).innerHTML;
                    }
                    this.each(function(){
                            this.innerHTML = content;
                    });
                    return this;
            },
            //9.3 获取指定元素的 text 内容
            'text':function(content){
                    if(content === undefined){
                            var resultStr = '';
                            this.each(function(){
                                    resultStr += this.innerText;
                            });
                            return resultStr;
                    }
                    if($.isFuntion(content)){
                            this.each(function(index,value){
                                    this.innerText = content(index,this.innerText)
                            });
                            return this;
                    }
                    this.each(function(){
                            this.innerText = content;
                    });
                    return this;
            },
            //9.4追加元素到另外一个元素中
            //下面几个方法类似
            //注意,测试先后顺序,分清插入的位置即可
            //注意核心代码的实现,然后再扩展业务逻辑
            'appendTo':function(content){
                    content = $(content);
                    var source = this;
                    var target = content;
                    target.each(function(t_index,t_value){
                            source.each(function(s_index,s_value){
                                    if(t_index == 0){
                                            t_value.appendChild(s_value);
                                    }else{
                                            var clone = s_value.cloneNode(true);
                                            t_value.appendChild(clone);
                                    }
                            })
                    });
                    return this;
            },
            ‘prependTo’:function(content){
                    content = $(content);
                    var source = this;
                    var target = content;
                    target.each(function(t_index,t_value){
                            source.reverse().each(function(s_index,s_value){
                                      if(t_index == 0){
                                              //t_value.appendChild(s_value);
                                              t_value.inertBefore(s_value,t_value.firstChild);
                                      }else{
                                              var clone = s_value.cloneNode(true);
                                              //t_value.appendChild(clone);
                                              t_value.insetBefore(clone,t_value.firstChild);
                                      }
                              })
                    });
                    return this;
            },
            'prepend':function(content){
                    if($.isObject(content)){
                          var source = content;
                          var target = this;
                          source.prependTo(target);
                          return this;          
                    }
                    this.each(function(){
                            // this == DOM 对象
                            this.innerHTML = content + this.innerHTML;
                    });
                    return this;
            },
            'append':function(content){
                    if($.isObject(content)){
                            var source = content;
                            var target = this;
                            source.appendTo(target);
                            return this;
                    }
                    this.each(function(){
                            //this == DOM 对象
                            this.innerHTML = this.innerHTML + content;
                    });
                    return this;
            }
    });
    //10.DOM 样式的获取
    //注意浏览器兼容
    //此处需要掌握:了解样式的分类,以及基本的获取方式
    szjQuery.extend({
            'getStyle':function(dom){
                    if($.isDOM(dom)){
                            var finalStyle = dom.currentStyle ? dom.currentStyle : window.getComputedStyle(dom,null);
                            return finalStyle;
                    }
            }
    });
    /*
    *11.DOM 节点属性的操作
    *包括,操作属性,操作节点属性,修改/获取 CSS 样式
    *获取/设置 value 值
    *判断类,新增、删除、切换类
    *事件添加和移除
    *注意:
    *此段代码的开发,思路如下
    *1.需要考虑核心的代码是什么?
    *2.大部分都是批量操作,所以,从小工能开始实现,然后慢慢按照需求进行扩展
    *3.千万不要一次性的从最大的功能开始左
    *4.不要求实现的一模一样,只需要直到一个大概逻辑,有个简单基本实现就好
    *5.容错性逻辑,最后统一处理,放置我们观察主要逻辑
    *6.关于一些类名的判断,全部都是靠字符串之间的关系进行处理
    *注意容错
    */
    szjQuery.prototype.extend({
            //操作节点属性
            'attr':function(){
                    if(arguments.length === 1){
                            var value = arguments[0];
                            //1.如果是字符串
                            if($.isString(value)){
                                    //获取第一个 DOM 对象的对应的节点属性值
                                    return this[0].getAttribute(value);
                            }
                            //2.如果是对象
                            if($.isObject(value)){
                                    //批量的设置 DOM 对象里面的节点属性值
                                    this.each(function(index,dom){
                                            $.each(value,function(key,value){
                                                    dom.setAttribute(key,value);
                                            })
                                    });
                                    return this;     
                            }
                    }
                    //arguments,this,return
                    if(arguments.length === 2 && $.isString(arguments[0])){
                            var key = arguments[0];
                            var value = arguments[1];
                            //遍历所有的 DOM 对象
                            this.each(function(index,dom){
                                    dom.setAttribute(key,value);
                            });
                            return this;
                    }
                    throw '请输入正确的参数';
            },
            'removeAttr':function(){
                    var firstParam = arguments[0];
                    if($.isString(firstParam)){
                            this.each(function(index,dom){
                                    dom.removeAttribute(firstParam);
                            })
                    }
                    return this;
            },
            'prop':function(){
                    if(arguments.length === 1){
                            var value = arguments[0];
                            //1.如果是字符串
                            if($.isString(value)){
                                    //获取第一个 DOM 对象的对应的属性值
                                    return this[0][value];
                                    //this['name'];
                                    //this.name
                            }
                            //2.如果是对象
                            if($.isObject(value)){
                                    //批量的设置 DOM 对象里面的属性值
                                    this.each(function(index,dom){
                                            $.each(value,function(key,value){
                                                    dom[key] = value;
                                            })
                                    })
                                    return this;
                            }
                    }
                    if(arguments.length === 2 && $.isString(arguments[0])){
                            var key = arguments[0];
                            var value = arguments[1];
                            //遍历所有的 DOM 对象
                            this.each(function(index,dom){
                                    dom[key] = value;
                            });
                            return this;
                    }
                    throw '请输入正确的参数';
            },
            'removeProp':function(){
                    var firstParam = arguments[0];
                    if($.isString(firstParam)){
                            this.each(function(index,dom){
                                    delete dom[firstParam];
                            })
                    }
                    return this;
            },
            'CSS':function(){
                    if(arguments.length === 1){
                            var value = arguments[0];
                            //1.如果是字符串
                            if($.isString(value)){
                                    //value == background width
                                    //获取第一个 DOM 对象里面的样式属性
                                    var dom = this[0];
                                    return $.getStyle(dom)[value];
                            }
                            //2.如果是对象
                            if($is.Object(value)){
                                    //批量的设置 DOM 对象里面的批量样式属性值
                                    this.each(function(){
                                            $.each(value,function(index,dom){
                                                    //dom.setAttribute(key,value);
                                                    dom.style[key] = value;
                                            })
                                    });
                                    return this;
                            }
                    }
                    if(arguments.length === 2 && $.isString(arguments[0])){
                            var key = arguments[0];
                            var value = arguments[1];
                            //遍历所有的 DOM 对象
                            this.each(function(index,dom){
                                    dom.style[key] = value;
                            });
                            return this;
                    }
                    throw '请输入正确的参数';
            },
            'val':funciton(firstParam){
                    if(firstParam === undefined){
                            var dom = this[0];
                            //return dom.getAttribute('value');  这种写法是错误的无法实时获取更新了的数值
                            return dom['value'];
                    }else{
                            //批量的给所有的 DOM 对象,赋值 value
                            this.each(function(index,dom){
                                    dom['value'] = firstParam;
                            });
                            return this;
                    }
            },
            ‘hasClass’:function(firstParam){
                    if(firstParam === undefined){
                            return false;
                    }
                    // 'box111' 'box1' '  box1'
                    // ' box1 ' 
                    if($.isString(firstParam)){
                            var trimClassName = ' ' + $.trimString(firstParam) + ' ';
                            var hasClass = false;
                            this.each(function(index,dom){
                                    var parentClassName = ' ' + $.trimString(dom.className) + ' ';
                                    var searchIndex = parentClassName.indexOf(trimClassName);
                                      if(searchIndex >= 0){
                                                hasClass = true; 
                                                //结束遍历
                                                return false'     
                                      }
                            });
                            return hasClass;
                    }
            },
            'addClass':function(firstParam){
                    if(firstParam === undefined){
                            return this;
                    }
                    if($.isString(firstParam)){
                            //1.遍历所有的 dom 对象
                            this.each(function(index,dom){
                                    //先获取给定的类名数组
                                    var classNameArr = $.trimSpaceArrayWithStr(firstParam);
                                    $.each(classNameArr,function(index,className){
                                            if(!$(dom).hasClass(className)){
                                                    dom.className = dom.className + ' ' + className;
                                            }
                                    });
                                    //格式化, dom 的类名
                                    var resultClassNames = $.trimSpaceArrayWithStr(dom.className);
                                    //按照指定的字符,链接所有的元素,-》字符串,就是 join 的作用
                                      dom.className = resultClassNames.join(' ');
                            });
                    }
                    return this;
            },
            'removeClass':function(firstParam){
                    if(firstParam === undefined ){
                            //清空所有 DOM 对象里面的类名
                            this.each(function(index,dom){
                                    dom.className = '';
                            });
                            return this;
                    }
                    //'box1 box2'
                    //'box1'
                    //'box1 box2'
                    if($.isString(firstParam)){
                            //'box1'
                            //var searchClassName = ' ' + $.trimString(firstParam) + ' ';
                            //'   box1   box2  '
                            //['box1','box2']
                            var searchClassNames = $.trimSpaceArrayWithStr(firstParam);
                            //遍历所有的 DOM 对象
                            this.each(function(index,dom){
                                    //判断 DOM 对象的 className,是否包含指定的类名
                                    var parentClassName = ' ' + dom.className + ' ';
                                    //针对于每一个 DOM 对象
                                    //删除,一个类名 集合
                                    $.each(searchClassNames,function(){
                                              //如果包含,则删除
                                              if($(dom).hasClass(searchClassName)){
                                                      parentClassName = parentClassName.replace(searchClassName,'
     ');
                                              }
                                      });
                                      //代表该删除的,已经删除完毕
                                      //dom.className = parentClassName;
                                      //['box1','box2','box3']
                                      //'box1 box2 box3'
                                      var classNameArr = #.trimSpaceArrayWithStr(parentClassName);
                                      dom.className = classNameArr.join(' ');
                            })
                    }
                    return this;
            },
            'toggleClass':function(firstParam){
                    if(firstParam  === undefined){
                            this.each(function(index,dom){
                                    if(dom.className.length > 0){
                                            //永远有值
                                            dom['orginClassName'] = dom.className;
                                    }
                                    //格式化 className
                                    var resultClassName = dom.className === ' ' ? dom['orginClassName'] : ' ';
                                    dom.className = $trimSpaceArrayWithStr(resultClassName).join(' ');        
                            });
                            return this;
                    }
                    if($.isString(firstParam)){
                            //firstParam == '   box1   box2 '
                            var searchClassNames = $.trimSpaceArrayWithStr(firstParam);
                            //firstParam == 'box1'
                            //让每一个 DOM 对象,都切换给定的类名
                            this.each(function(index,dom){
                                      $.each(searchClassName,function(index,searchClassName){
                                            //判断是否有这个类名
                                            //有就删除没有就添加
                                            if($(dom).hasClass(searchClassName)){
                                                    $(dom).removeClass(searchClassName);
                                            }else{
                                                    $(dom).addClass(searchClassName);
                                            }
                                    })
                            });
                            return this;
                    }
            }
    });
    /*
    *12 添加基本的事件监听和移除方法
    *注意浏览器的兼容
    *以及以后开发工具类的时候,工具类方法的类型
    *是选择对象方法,还是使用静态方法
    *主要区分依据,就是看下在方法内部是否可以借助 this 对象中的属性获取其他信息
    *如果不需要,则统一使用静态方法进行实现
    */
    $.extend({
            'addEvent':function(ele,type,func){
                    //0.容错处理
                    if(!$.isDOM(ele) || !$.isString(type) || isFunction(func)){
                            return;
                    }
                    //1.根据传递过来的参数,进行事件的监听
                    if(ele.addEventListener){
                            ele.addEventListner(type,func)
                    }else{
                            ele.attachEvent('on' + type ,func)
                    }
                    return;
            },
            'removeEvent':function(ele,type,func){
                    if(!$.isDOM(ele) || $.isString(type) || $.isFunction(func)){
                            return;
                    }
                    //1.根据传递过来的参数,进行事件的监听
                    if(ele.removeEventListener){
                            ele.removeEventListener(type,func);         
                    }else{
                            ele.detachEvent('on' + type,func);
                    }
                    return;
            }
    });
    /*
    *13.批量操作事件绑定,和事件解绑的方法
    *此处注意开发步骤
    *先从最基本,最小的功能开始左
    *比如可以先看下一个 dom 对象,添加一个事件类型,绑定一个回调函数的时候是如何实现的
    *然后慢慢进行扩展多个类型的
    *多个回调函数的
    *多个 DOM 对象的
    *以此类推
    */
    $.prototype.extend({
            //一个类型,一个回调函数,多个DOM 对象的情况
            '_on':function(type,func){
                    //批量给 DOM 对象,添加事件
                    this.each(function(index,dom){
                            $.addEvent(dom,type,func)
                    })
            },
            //多个类型,一个回调函数,多个 DOM 对象的情况
            '_on2':function(types,func){
                    //批量给 DOM 对象,添加事件
                    var typeArray = $.trimSpaceArrayWithStr(types);
                    this.each(function(index,type){
                            $.each(typeArray,function(index,type){
                                    $.addEvent(dom,type,func)
                            })
                    })
            },
            //多个类型,多个回调函数,多个 DOM 对象的情况
            '_on3':function(firstParam){
                    //当事件绑定的时候
                    if(arguments.length === 1){
                            if(!$.isObject(firstParam)){
                                    return this;
                            }
                            this.each(function(index,dom){
                                    $.each(firstParam,function(type,func){
                                            $.addEvent(dom,type,func);
                                    })
                            });
                            return this;
                    }
                    if(arguments.length === 2){
                            //'click dbclick mouseover',func
                            //批量给 DOM 对象,添加事件
                            var typeArray = $.trimSpaceArrayWithStr(arguments[0]);
                            var func = arguments[1];
                            this.each(function(index.dom){
                                    $.each(typeArray,function(index,type){
                                              $.addEvent(dom,type,func);
                                      })
                            })
                    }
            },
            //为了存储,监听的事件信息,方便解绑
            'on':function(firstParam){
                    //当事件绑定的时候,把这个 DOM 对象身上的事件类型,和事件回调都给记录下来
                    if(arguments.length === 1){
                            if(!$.isObject(firstParam)){
                                    return this;
                            }
                            this.each(function(index,dom){
                                    //1.给 dom, 新增一个属性
                                    dom['eventCache'] = dom['eventCache'] || [];
                                    $.each(firstParam,function(type,func){
                                              $.addEvent(dom,type,func);
                                              dom['eventCache'][type] = dom['eventCache'][type] || [];
                                              dom['eventCache'][type].push(func);
                                      })
                            });
                            return this;
                    }
                    if(arguments.length ===2){
                            var typeArray = $.trimSpaceArrayWithStr(argument[0]);
                            var func = arguments[1];
                            this.each(function(index,dom){
                                    dom['eventCache'] = dom['eventCache'] || [];
                                    $.each(typeArray,function(index,type){
                                            $.addEvent(dom,type,func);
                                            dom['eventCache'][type] = dom['eventCache'][type] || [];
                                            dom['eventCache'][type].push(func);
                                    })
                            })
                    }
            },
            //解绑多个 DOM 对象,一个事件类型的情况
            '_off':function(type){
                    //type === 'click'
                    this.each(funcntion(index,dom){
                            var funcs = dom['eventCache'][type];
                            $each(funcs,function(index,func){
                                    $.removeEvent(dom,type,func);
                            })
                    });
                    return this;
            },
            //解绑多个 DOM 对象,多个事件类型的情况
            '_off2':function(types){
                    var typeArr = $.trimSpaceArrayWithStr(types);
                    this.each(function(index,dom){
                              $.each(typeArr,function(index,type){
                                      //找到类型对应的回调函数组
                                      var funcs = dom['eventCache'][type];
                                      //解绑函数
                                      $.each(funcs,function(index,func){
                                              $.removeEvent(dom,type,func)
                                      })
                              })
                    });
                    return this;
            },
    /*
    *解绑多个DOM 对象,一个事件类型 指定回调函数的情况
    *注意:吃出的开发,需要结合 on 方法内部,先记录下,当前对象绑定的事件信息
    */
                    'off': function (types, paramFunc) {
                //  type === 'click'
                var typeArr = $.trimSpaceArrayWithStr(types);
    
                // 遍历所有的DOM对象
                this.each(function (index, dom) {
                    console.log(dom['eventCache']);
                    // 遍历所有的事件类型
                    $.each(typeArr, function (index, type) {
                        // 找到类型对应的回调函数数组
                        var funcs = dom['eventCache'][type];
    
                        // 解绑函数
                        // 遍历所有的函数
                        $.each(funcs, function (index, func) {
    
                            // 处理指定函数这个参数没有传递的情况
                            if (paramFunc === undefined) {
                                $.removeEvent(dom, type, func);
                            }
                            // 处理指定函数 这个参数传递的情况
                            if (func === paramFunc) {
                                // 解绑
                                $.removeEvent(dom, type, func);
                            }
                        })
                    })
                });
                return this;
    
            }
    })
    })(window)
    
    

    相关文章

      网友评论

          本文标题:2017-04-17 jQuery 原理

          本文链接:https://www.haomeiwen.com/subject/dgozattx.html