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)