2017-04-17 jQuery 原理

jQuery 的內(nèi)部實現(xiàn)

  • 課程目標(biāo)

  • 需要掌握
    了解常用方法的使用
    掌握常用方法的底層實現(xiàn)邏輯
    學(xué)會根據(jù)一個目標(biāo)需求,來根據(jù)自己的思想編寫出大致實現(xiàn)
    了解一些編寫框架的技巧蹦哼,比如為什么用閉包蒜危,為什么傳遞 window 參數(shù)
    了解一些機制攘乒,比如插件機制设预,如何擴展一些方法或者屬性
    要求掌握面向?qū)ο蟮乃枷肴ソ鉀Q問題脐彩,熟練了解原型碎乃, this 指針等概念

  • 整體是一個執(zhí)行的閉包
    這樣寫的主要目的是為了防止內(nèi)部一些功能被污染

  • 傳遞 window 參數(shù)
    是為了方便亞索,以及提高檢索效率

  • 內(nèi)部接收 undefined
    是為了放置惠奸,外界修改 undefined 所代表的含義

  • 內(nèi)部的參數(shù)梅誓,如何讓外界可以訪問
    可以通過給 window 對象,動態(tài)的增加屬性佛南,暴露給外界調(diào)用

(function(){
        //1.定義構(gòu)造函數(shù)
        var szjQuery = function(selector){
                //內(nèi)部 new 了一個對象返回給外界梗掰,讓外界使用方便,沒必要再創(chuàng)建
                return new szjQuery.prototype.init(selector);
        }
        //2.修改函數(shù)的原型
        //以后嗅回,可以在這個位置擴展一些屬性及穗,或者方法
        //注意:這里有個比較重要的方法 init 方法,基本上所有的創(chuàng)建 jQuery 對象初始化的邏輯绵载,都是在這個函數(shù)里面進行處理的
        szjQuery.prototype = {
                szjQuery:'1.1.0',
                selector:'',
                length:0,
                constructor:szjQuery,
                init:function(){
                        //this.length = 0;
                        //在這里處理 selector 傳進來的參數(shù)
                        //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] 來實現(xiàn)
                                        [].push.apply(this,firstChildren);
                                        return this;
                                }
                                //2.2要不就是選擇器
                                var tags = document.querySelectorAll(selector);
                                [].push.apply(this,tags);
                                return this;      
                        } 
                        //3.判定是否是偽數(shù)組/真數(shù)組
                        if($.isWindow(selector) && $.isLikeArray(selector)){
                                [].push.apply(this,selector);
                                return this;    
                        } 
                        //4.判斷是否是一個函數(shù)
                        if($.isFunction(selector)){
                                $.ready(selector);
                        } 
                        //其他
                        //DOM 基本對象 基本數(shù)據(jù)類型 1234
                        this[0] = selector;
                        this.length = 1;
                        return this;                    
                }        
        };
        //3.創(chuàng)建一個快速批量創(chuàng)建靜態(tài)方法/實例方法的方法
        //因為內(nèi)部的 this 埂陆,是動態(tài)指向調(diào)用者的
        //所以苛白,可以借助這個特性,來動態(tài)的給對象或者方法添加方法
        szjQuery.extend = szjQuery.prototype.extend = function(funDic){
                for(var key in funDic){
                        this[key] = funDic[key];
                }        
        }
        //4.重新修改 init 函數(shù)的原型指向焚虱,避免方法調(diào)用不到的問題
        //此處必須了解以下幾點
        //4.1每個函數(shù)都有對應(yīng)的原型對象
        //4.2通過什么構(gòu)造函數(shù)购裙,創(chuàng)建出來的實例對象,這個對象的 __proto__ 就指向該構(gòu)造函數(shù)的原型對象
        //4.3當(dāng)調(diào)用一個對象方法的時候鹃栽,是根據(jù) __proto__ 來進行查找方法的
        //4.4所以躏率,當(dāng)一個對象找不到方法,應(yīng)該注意查看該對象的構(gòu)造函數(shù)的
        //4.5注意民鼓,任何一個函數(shù)的原型薇芝,都可以修改
        szjQuery.prototype.init.prototype = szjQuery.prototype;
        //通過 window 對象,將內(nèi)部對象暴露給外界
        //因為丰嘉,基本上夯到,所有的功能都是依附于 jQuery 對象存在的
        //所以,可以jQuery 對象給外界供嚎,然后其他的信息黄娘,會被間接的暴露出去
        window.szjQuery = window.$ = szjQuery;
        //6.擴展靜態(tài)方法
        //工具類,判斷類的是否是字符串克滴,是否是對象等等
        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;
                },
                //是否是偽數(shù)組
                '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
                },
                //是否是函數(shù)
                'isFunction':function(fun){
                        return typeof fun === 'function';
                },
                //是否是 DOM 對象
                'isDOM':function(dom){
                        if('nodeType' in dom){
                                return true;
                        }
                        return false;
                },
                //入口函數(shù)的處理
                //需要注意執(zhí)行時機,以及執(zhí)行次數(shù)
                'ready':function(func){
                        if(!$.isFunction(func)){
                                return;
                        }
                        //1.判斷當(dāng)前文檔是否已經(jīng)加載完畢
                        //直接執(zhí)行
                        //document.readyState 可以兼容當(dāng)前所有主流瀏覽器
                        var state = document.readyState;
                        if(state === 'complete'){
                                func();
                                return;
                        }
                        //2.如果沒有加載完畢
                        //監(jiān)聽 DOM 樹建立完成
                        // IE9+
                        if(document.addEventListener){
                                document.addEventListener('DOMContentloaded',func);
                                return;
                        }
                        // IE8
                        document.attachEvent('onreadystatechange',function(){
                                var state = document.readyState;
                                if(state === 'complete'){
                                        func();
                                }
                        });
                }
        });
//擴展實例方法
//數(shù)組相關(guān)的一些方法
//比如轉(zhuǎn)換稱為數(shù)組劝赔,遍歷誓焦,切割數(shù)組等等
//此處需要掌握,數(shù)組操作的常用方法的內(nèi)部實現(xiàn)
szjQuery.prototype.extend({
        //將偽數(shù)組着帽,轉(zhuǎn)換成為真數(shù)組
        '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 對象
        //可以考慮,借助其他已經(jīng)實現(xiàn)過的方法仍翰,進行處理
        //因為赫粥,內(nèi)部的邏輯大致和 get 方法類似
        'eq':function(index){
                if(index === undefined){
                        return $('');
                }
                return $(this.get(index));
        },
        //7.4獲取第一個的 DOM 元素,包裝的 jQuery 對象
        //可以考慮予借,借助其他已經(jīng)實現(xiàn)國的方法越平,進行處理
        //因為,內(nèi)部的邏輯灵迫,大致和 get 方法類似
        'first':function(){
                return this.eq(0);
        },
        //7.5 獲取最后一個的 DOM 元素秦叛,包裝 jQuery 對象
        //可以考慮,借助其他已經(jīng)實現(xiàn)的方法瀑粥,進行處理
        //因為挣跋,內(nèi)部的邏輯,大致和 get  方法類似
        'last':function(){
                return this.eq(-1);
        },
        //[].splice 獲取的是方法實現(xiàn)
        //7.6一定要注意狞换,jQuery 對象里面的避咆,這些方法的實現(xiàn)舟肉,其實和數(shù)組的這些方法實現(xiàn)一模一樣
        //所以,此處牌借,可以直接把數(shù)組對應(yīng)方法的實現(xiàn)放在這里
        //這樣度气,到時候,外界調(diào)用的時候膨报,就會按照相同的操作數(shù)組的邏輯,來操作 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.靜態(tài)方法
//數(shù)組相關(guān)
szjQuery.extend({
        //8.1 遍歷數(shù)組适荣,或者偽數(shù)組现柠,或者對象
        //內(nèi)部注意不同類型的處理
        //還有就是,此方法弛矛,支持對象方法够吩,和靜態(tài)方法
        //一般碰到這種情況,我們優(yōu)先開發(fā)靜態(tài)方法丈氓,然后再在實例方法中周循,調(diào)用靜態(tài)方法實現(xiàn)即可
        '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;
                }
                //不是偽數(shù)組
                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可以將一個字符串的空格,都給亞索万俗,然后把里面的有效元素湾笛,存儲到一個數(shù)組中
        //可以用來做一些格式化的操作
        '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 操作的相關(guān)方法
//注意:如果想要仿照一個功能
//先對這個功能進行充分的測試
//報錯參數(shù) 參數(shù)個數(shù) 參數(shù)類型 返回值等信息
szjQuery.prototype.extend({
        //9.1 清空 DOM 對象里面的內(nèi)容
        '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 內(nèi)容
        'html':function(content){
                if(content === undefined){
                        return this.get(0).innerHTML;
                }
                this.each(function(){
                        this.innerHTML = content;
                });
                return this;
        },
        //9.3 獲取指定元素的 text 內(nèi)容
        '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追加元素到另外一個元素中
        //下面幾個方法類似
        //注意,測試先后順序闰歪,分清插入的位置即可
        //注意核心代碼的實現(xiàn)嚎研,然后再擴展業(yè)務(wù)邏輯
        '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 節(jié)點屬性的操作
*包括库倘,操作屬性临扮,操作節(jié)點屬性,修改/獲取 CSS 樣式
*獲取/設(shè)置 value 值
*判斷類教翩,新增杆勇、刪除、切換類
*事件添加和移除
*注意:
*此段代碼的開發(fā)饱亿,思路如下
*1.需要考慮核心的代碼是什么蚜退?
*2.大部分都是批量操作,所以路捧,從小工能開始實現(xiàn)关霸,然后慢慢按照需求進行擴展
*3.千萬不要一次性的從最大的功能開始左
*4.不要求實現(xiàn)的一模一樣,只需要直到一個大概邏輯杰扫,有個簡單基本實現(xiàn)就好
*5.容錯性邏輯队寇,最后統(tǒng)一處理,放置我們觀察主要邏輯
*6.關(guān)于一些類名的判斷章姓,全部都是靠字符串之間的關(guān)系進行處理
*注意容錯
*/
szjQuery.prototype.extend({
        //操作節(jié)點屬性
        'attr':function(){
                if(arguments.length === 1){
                        var value = arguments[0];
                        //1.如果是字符串
                        if($.isString(value)){
                                //獲取第一個 DOM 對象的對應(yīng)的節(jié)點屬性值
                                return this[0].getAttribute(value);
                        }
                        //2.如果是對象
                        if($.isObject(value)){
                                //批量的設(shè)置 DOM 對象里面的節(jié)點屬性值
                                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 '請輸入正確的參數(shù)'佳遣;
        }识埋,
        '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 對象的對應(yīng)的屬性值
                                return this[0][value];
                                //this['name'];
                                //this.name
                        }
                        //2.如果是對象
                        if($.isObject(value)){
                                //批量的設(shè)置 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 '請輸入正確的參數(shù)';
        },
        '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)){
                                //批量的設(shè)置 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 '請輸入正確的參數(shù)';
        },
        'val':funciton(firstParam){
                if(firstParam === undefined){
                        var dom = this[0];
                        //return dom.getAttribute('value');  這種寫法是錯誤的無法實時獲取更新了的數(shù)值
                        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; 
                                            //結(jié)束遍歷
                                            return false'     
                                  }
                        });
                        return hasClass;
                }
        },
        'addClass':function(firstParam){
                if(firstParam === undefined){
                        return this;
                }
                if($.isString(firstParam)){
                        //1.遍歷所有的 dom 對象
                        this.each(function(index,dom){
                                //先獲取給定的類名數(shù)組
                                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,'
 ');
                                          }
                                  });
                                  //代表該刪除的风宁,已經(jīng)刪除完畢
                                  //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 添加基本的事件監(jiān)聽和移除方法
*注意瀏覽器的兼容
*以及以后開發(fā)工具類的時候,工具類方法的類型
*是選擇對象方法戒财,還是使用靜態(tài)方法
*主要區(qū)分依據(jù)热监,就是看下在方法內(nèi)部是否可以借助 this 對象中的屬性獲取其他信息
*如果不需要,則統(tǒng)一使用靜態(tài)方法進行實現(xiàn)
*/
$.extend({
        'addEvent':function(ele,type,func){
                //0.容錯處理
                if(!$.isDOM(ele) || !$.isString(type) || isFunction(func)){
                        return;
                }
                //1.根據(jù)傳遞過來的參數(shù)饮寞,進行事件的監(jiān)聽
                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.根據(jù)傳遞過來的參數(shù)孝扛,進行事件的監(jiān)聽
                if(ele.removeEventListener){
                        ele.removeEventListener(type,func);         
                }else{
                        ele.detachEvent('on' + type,func);
                }
                return;
        }
});
/*
*13.批量操作事件綁定,和事件解綁的方法
*此處注意開發(fā)步驟
*先從最基本幽崩,最小的功能開始左
*比如可以先看下一個 dom 對象苦始,添加一個事件類型,綁定一個回調(diào)函數(shù)的時候是如何實現(xiàn)的
*然后慢慢進行擴展多個類型的
*多個回調(diào)函數(shù)的
*多個 DOM 對象的
*以此類推
*/
$.prototype.extend({
        //一個類型歉铝,一個回調(diào)函數(shù)盈简,多個DOM 對象的情況
        '_on':function(type,func){
                //批量給 DOM 對象,添加事件
                this.each(function(index,dom){
                        $.addEvent(dom,type,func)
                })
        },
        //多個類型太示,一個回調(diào)函數(shù)柠贤,多個 DOM 對象的情況
        '_on2':function(types,func){
                //批量給 DOM 對象,添加事件
                var typeArray = $.trimSpaceArrayWithStr(types);
                this.each(function(index,type){
                        $.each(typeArray,function(index,type){
                                $.addEvent(dom,type,func)
                        })
                })
        },
        //多個類型类缤,多個回調(diào)函數(shù)臼勉,多個 DOM 對象的情況
        '_on3':function(firstParam){
                //當(dāng)事件綁定的時候
                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);
                                  })
                        })
                }
        },
        //為了存儲餐弱,監(jiān)聽的事件信息宴霸,方便解綁
        'on':function(firstParam){
                //當(dāng)事件綁定的時候,把這個 DOM 對象身上的事件類型膏蚓,和事件回調(diào)都給記錄下來
                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){
                                  //找到類型對應(yīng)的回調(diào)函數(shù)組
                                  var funcs = dom['eventCache'][type];
                                  //解綁函數(shù)
                                  $.each(funcs,function(index,func){
                                          $.removeEvent(dom,type,func)
                                  })
                          })
                });
                return this;
        },
/*
*解綁多個DOM 對象驮瞧,一個事件類型 指定回調(diào)函數(shù)的情況
*注意:吃出的開發(fā)氓扛,需要結(jié)合 on 方法內(nèi)部,先記錄下,當(dāng)前對象綁定的事件信息
*/
                '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) {
                    // 找到類型對應(yīng)的回調(diào)函數(shù)數(shù)組
                    var funcs = dom['eventCache'][type];

                    // 解綁函數(shù)
                    // 遍歷所有的函數(shù)
                    $.each(funcs, function (index, func) {

                        // 處理指定函數(shù)這個參數(shù)沒有傳遞的情況
                        if (paramFunc === undefined) {
                            $.removeEvent(dom, type, func);
                        }
                        // 處理指定函數(shù) 這個參數(shù)傳遞的情況
                        if (func === paramFunc) {
                            // 解綁
                            $.removeEvent(dom, type, func);
                        }
                    })
                })
            });
            return this;

        }
})
})(window)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末采郎,一起剝皮案震驚了整個濱河市千所,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蒜埋,老刑警劉巖淫痰,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異整份,居然都是意外死亡待错,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門皂林,熙熙樓的掌柜王于貴愁眉苦臉地迎上來朗鸠,“玉大人,你說我怎么就攤上這事础倍。” “怎么了胎挎?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵沟启,是天一觀的道長。 經(jīng)常有香客問我犹菇,道長德迹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任揭芍,我火速辦了婚禮胳搞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘称杨。我一直安慰自己肌毅,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布姑原。 她就那樣靜靜地躺著悬而,像睡著了一般。 火紅的嫁衣襯著肌膚如雪锭汛。 梳的紋絲不亂的頭發(fā)上笨奠,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天,我揣著相機與錄音唤殴,去河邊找鬼般婆。 笑死,一個胖子當(dāng)著我的面吹牛朵逝,可吹牛的內(nèi)容都是我干的蔚袍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼廉侧,長吁一口氣:“原來是場噩夢啊……” “哼页响!你這毒婦竟也來了篓足?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤闰蚕,失蹤者是張志新(化名)和其女友劉穎栈拖,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體没陡,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡涩哟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了盼玄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贴彼。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖埃儿,靈堂內(nèi)的尸體忽然破棺而出器仗,到底是詐尸還是另有隱情,我是刑警寧澤童番,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布精钮,位于F島的核電站,受9級特大地震影響剃斧,放射性物質(zhì)發(fā)生泄漏轨香。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一幼东、第九天 我趴在偏房一處隱蔽的房頂上張望臂容。 院中可真熱鬧,春花似錦根蟹、人聲如沸脓杉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽丽已。三九已至,卻和暖如春买决,著一層夾襖步出監(jiān)牢的瞬間沛婴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工督赤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留嘁灯,地道東北人。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓躲舌,卻偏偏與公主長得像丑婿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,116評論 25 707
  • 在線閱讀 http://interview.poetries.top[http://interview.poetr...
    程序員poetry閱讀 114,381評論 24 450
  • 中學(xué)時代羹奉,我羨慕道明寺對杉菜的霸道秒旋,羨慕湘琴對直樹的執(zhí)著,羨慕李逍遙對趙靈兒的深情诀拭。 我經(jīng)常會望著教室窗外傻傻發(fā)呆...
    洪木木閱讀 595評論 0 0
  • 第一次畫蓮花迁筛。以前看那些孩子怎么可以把蓮花畫的那么漂亮,為了避免自尊心受到傷害耕挨,所以一直不敢嘗試细卧,今天翻來翻去還是...
    碎碎碎發(fā)隨風(fēng)吹閱讀 426評論 2 2
  • 最近一直在地鐵上看《曾國藩家書》,這本書第一次看是在大學(xué)筒占,在圖書館翻了翻就放下了贪庙,當(dāng)時看書急功近利,只想著看完翰苫,而...
    顏先生閱讀 2,079評論 0 3