jQuery 的內(nèi)部實(shí)現(xiàn)
課程目標(biāo)
需要掌握
了解常用方法的使用
掌握常用方法的底層實(shí)現(xiàn)邏輯
學(xué)會(huì)根據(jù)一個(gè)目標(biāo)需求,來根據(jù)自己的思想編寫出大致實(shí)現(xiàn)
了解一些編寫框架的技巧,比如為什么用閉包,為什么傳遞 window 參數(shù)
了解一些機(jī)制,比如插件機(jī)制,如何擴(kuò)展一些方法或者屬性
要求掌握面向?qū)ο蟮乃枷肴ソ鉀Q問題,熟練了解原型, this 指針等概念整體是一個(gè)執(zhí)行的閉包
這樣寫的主要目的是為了防止內(nèi)部一些功能被污染傳遞 window 參數(shù)
是為了方便亞索,以及提高檢索效率內(nèi)部接收 undefined
是為了放置,外界修改 undefined 所代表的含義內(nèi)部的參數(shù),如何讓外界可以訪問
可以通過給 window 對(duì)象,動(dòng)態(tài)的增加屬性,暴露給外界調(diào)用
(function(){
//1.定義構(gòu)造函數(shù)
var szjQuery = function(selector){
//內(nèi)部 new 了一個(gè)對(duì)象返回給外界,讓外界使用方便,沒必要再創(chuàng)建
return new szjQuery.prototype.init(selector);
}
//2.修改函數(shù)的原型
//以后,可以在這個(gè)位置擴(kuò)展一些屬性,或者方法
//注意:這里有個(gè)比較重要的方法 init 方法,基本上所有的創(chuàng)建 jQuery 對(duì)象初始化的邏輯,都是在這個(gè)函數(shù)里面進(jìn)行處理的
szjQuery.prototype = {
szjQuery:'1.1.0',
selector:'',
length:0,
constructor:szjQuery,
init:function(){
//this.length = 0;
//在這里處理 selector 傳進(jìn)來的參數(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] 來實(shí)現(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.判斷是否是一個(gè)函數(shù)
if($.isFunction(selector)){
$.ready(selector);
}
//其他
//DOM 基本對(duì)象 基本數(shù)據(jù)類型 1234
this[0] = selector;
this.length = 1;
return this;
}
};
//3.創(chuàng)建一個(gè)快速批量創(chuàng)建靜態(tài)方法/實(shí)例方法的方法
//因?yàn)閮?nèi)部的 this ,是動(dòng)態(tài)指向調(diào)用者的
//所以,可以借助這個(gè)特性,來動(dòng)態(tài)的給對(duì)象或者方法添加方法
szjQuery.extend = szjQuery.prototype.extend = function(funDic){
for(var key in funDic){
this[key] = funDic[key];
}
}
//4.重新修改 init 函數(shù)的原型指向,避免方法調(diào)用不到的問題
//此處必須了解以下幾點(diǎn)
//4.1每個(gè)函數(shù)都有對(duì)應(yīng)的原型對(duì)象
//4.2通過什么構(gòu)造函數(shù),創(chuàng)建出來的實(shí)例對(duì)象,這個(gè)對(duì)象的 __proto__ 就指向該構(gòu)造函數(shù)的原型對(duì)象
//4.3當(dāng)調(diào)用一個(gè)對(duì)象方法的時(shí)候,是根據(jù) __proto__ 來進(jìn)行查找方法的
//4.4所以,當(dāng)一個(gè)對(duì)象找不到方法,應(yīng)該注意查看該對(duì)象的構(gòu)造函數(shù)的
//4.5注意,任何一個(gè)函數(shù)的原型,都可以修改
szjQuery.prototype.init.prototype = szjQuery.prototype;
//通過 window 對(duì)象,將內(nèi)部對(duì)象暴露給外界
//因?yàn)椋旧希械墓δ芏际且栏接?jQuery 對(duì)象存在的
//所以,可以jQuery 對(duì)象給外界,然后其他的信息,會(huì)被間接的暴露出去
window.szjQuery = window.$ = szjQuery;
//6.擴(kuò)展靜態(tài)方法
//工具類,判斷類的是否是字符串,是否是對(duì)象等等
szjQuery.extend({
//是否是字符串方法
'isString':function(){
return typeof str === 'string';
},
//可以壓縮字符串的首尾空格
//此處注意兼容,以及正則表達(dá)式的使用
'trimString':function(str){
if(str.trim){
return str.trim();
}
return str.replace(/^\s+|\s+$/g, '');
},
//判斷是否是窗口過對(duì)象
'isWindow': function(w){
return window.window !== w;
},
//是否是偽數(shù)組
'isLikeArray':function(){
return (this.isObject(arr) && 'length' in arr && (arr.length - 1) in arr);
},
//是否是對(duì)象
'isObject':function(obj){
return typeof obj === 'object';
},
//是否是代碼片段
//注意空格的容錯(cuò)處理
'isHTML':function(html){
return html.charAt(0) === '<' && html.charAt(html.length - 1) === '>' &&html.length > 3
},
//是否是函數(shù)
'isFunction':function(fun){
return typeof fun === 'function';
},
//是否是 DOM 對(duì)象
'isDOM':function(dom){
if('nodeType' in dom){
return true;
}
return false;
},
//入口函數(shù)的處理
//需要注意執(zhí)行時(shí)機(jī),以及執(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();
}
});
}
});
//擴(kuò)展實(shí)例方法
//數(shù)組相關(guān)的一些方法
//比如轉(zhuǎn)換稱為數(shù)組,遍歷,切割數(shù)組等等
//此處需要掌握,數(shù)組操作的常用方法的內(nèi)部實(shí)現(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獲取某個(gè)一個(gè) DOM 元素
//注意正負(fù)索引值的處理
'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 對(duì)象
//可以考慮,借助其他已經(jīng)實(shí)現(xiàn)過的方法,進(jìn)行處理
//因?yàn)椋瑑?nèi)部的邏輯大致和 get 方法類似
'eq':function(index){
if(index === undefined){
return $('');
}
return $(this.get(index));
},
//7.4獲取第一個(gè)的 DOM 元素,包裝的 jQuery 對(duì)象
//可以考慮,借助其他已經(jīng)實(shí)現(xiàn)國(guó)的方法,進(jìn)行處理
//因?yàn)椋瑑?nèi)部的邏輯,大致和 get 方法類似
'first':function(){
return this.eq(0);
},
//7.5 獲取最后一個(gè)的 DOM 元素,包裝 jQuery 對(duì)象
//可以考慮,借助其他已經(jīng)實(shí)現(xiàn)的方法,進(jìn)行處理
//因?yàn)椋瑑?nèi)部的邏輯,大致和 get 方法類似
'last':function(){
return this.eq(-1);
},
//[].splice 獲取的是方法實(shí)現(xiàn)
//7.6一定要注意,jQuery 對(duì)象里面的,這些方法的實(shí)現(xiàn),其實(shí)和數(shù)組的這些方法實(shí)現(xiàn)一模一樣
//所以,此處,可以直接把數(shù)組對(duì)應(yīng)方法的實(shí)現(xiàn)放在這里
//這樣,到時(shí)候,外界調(diào)用的時(shí)候,就會(huì)按照相同的操作數(shù)組的邏輯,來操作 jQuery 對(duì)象
'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ù)組,或者對(duì)象
//內(nèi)部注意不同類型的處理
//還有就是,此方法,支持對(duì)象方法,和靜態(tài)方法
//一般碰到這種情況,我們優(yōu)先開發(fā)靜態(tài)方法,然后再在實(shí)例方法中,調(diào)用靜態(tài)方法實(shí)現(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可以將一個(gè)字符串的空格,都給亞索,然后把里面的有效元素,存儲(chǔ)到一個(gè)數(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)方法
//注意:如果想要仿照一個(gè)功能
//先對(duì)這個(gè)功能進(jìn)行充分的測(cè)試
//報(bào)錯(cuò)參數(shù) 參數(shù)個(gè)數(shù) 參數(shù)類型 返回值等信息
szjQuery.prototype.extend({
//9.1 清空 DOM 對(duì)象里面的內(nèi)容
'empty':function(){
this.each(function(){
//index value value
//this 就是每一個(gè) DOM 對(duì)象
this.innerHTML = '';
});
return this;
},
//9.2 刪除指定的 DOM 對(duì)象
'remove':function(){
this.each(function(){
//this 是每一個(gè) DOM 對(duì)象
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追加元素到另外一個(gè)元素中
//下面幾個(gè)方法類似
//注意,測(cè)試先后順序,分清插入的位置即可
//注意核心代碼的實(shí)現(xiàn),然后再擴(kuò)展業(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 對(duì)象
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 對(duì)象
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é)點(diǎn)屬性的操作
*包括,操作屬性,操作節(jié)點(diǎn)屬性,修改/獲取 CSS 樣式
*獲取/設(shè)置 value 值
*判斷類,新增、刪除、切換類
*事件添加和移除
*注意:
*此段代碼的開發(fā),思路如下
*1.需要考慮核心的代碼是什么?
*2.大部分都是批量操作,所以,從小工能開始實(shí)現(xiàn),然后慢慢按照需求進(jìn)行擴(kuò)展
*3.千萬(wàn)不要一次性的從最大的功能開始左
*4.不要求實(shí)現(xiàn)的一模一樣,只需要直到一個(gè)大概邏輯,有個(gè)簡(jiǎn)單基本實(shí)現(xiàn)就好
*5.容錯(cuò)性邏輯,最后統(tǒng)一處理,放置我們觀察主要邏輯
*6.關(guān)于一些類名的判斷,全部都是靠字符串之間的關(guān)系進(jìn)行處理
*注意容錯(cuò)
*/
szjQuery.prototype.extend({
//操作節(jié)點(diǎn)屬性
'attr':function(){
if(arguments.length === 1){
var value = arguments[0];
//1.如果是字符串
if($.isString(value)){
//獲取第一個(gè) DOM 對(duì)象的對(duì)應(yīng)的節(jié)點(diǎn)屬性值
return this[0].getAttribute(value);
}
//2.如果是對(duì)象
if($.isObject(value)){
//批量的設(shè)置 DOM 對(duì)象里面的節(jié)點(diǎn)屬性值
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 對(duì)象
this.each(function(index,dom){
dom.setAttribute(key,value);
});
return this;
}
throw '請(qǐng)輸入正確的參數(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)){
//獲取第一個(gè) DOM 對(duì)象的對(duì)應(yīng)的屬性值
return this[0][value];
//this['name'];
//this.name
}
//2.如果是對(duì)象
if($.isObject(value)){
//批量的設(shè)置 DOM 對(duì)象里面的屬性值
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 對(duì)象
this.each(function(index,dom){
dom[key] = value;
});
return this;
}
throw '請(qǐng)輸入正確的參數(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
//獲取第一個(gè) DOM 對(duì)象里面的樣式屬性
var dom = this[0];
return $.getStyle(dom)[value];
}
//2.如果是對(duì)象
if($is.Object(value)){
//批量的設(shè)置 DOM 對(duì)象里面的批量樣式屬性值
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 對(duì)象
this.each(function(index,dom){
dom.style[key] = value;
});
return this;
}
throw '請(qǐng)輸入正確的參數(shù)';
},
'val':funciton(firstParam){
if(firstParam === undefined){
var dom = this[0];
//return dom.getAttribute('value'); 這種寫法是錯(cuò)誤的無法實(shí)時(shí)獲取更新了的數(shù)值
return dom['value'];
}else{
//批量的給所有的 DOM 對(duì)象,賦值 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 對(duì)象
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 對(duì)象里面的類名
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 對(duì)象
this.each(function(index,dom){
//判斷 DOM 對(duì)象的 className,是否包含指定的類名
var parentClassName = ' ' + dom.className + ' ';
//針對(duì)于每一個(gè) DOM 對(duì)象
//刪除,一個(gè)類名 集合
$.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){
//永遠(yuǎn)有值
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'
//讓每一個(gè) DOM 對(duì)象,都切換給定的類名
this.each(function(index,dom){
$.each(searchClassName,function(index,searchClassName){
//判斷是否有這個(gè)類名
//有就刪除沒有就添加
if($(dom).hasClass(searchClassName)){
$(dom).removeClass(searchClassName);
}else{
$(dom).addClass(searchClassName);
}
})
});
return this;
}
}
});
/*
*12 添加基本的事件監(jiān)聽和移除方法
*注意瀏覽器的兼容
*以及以后開發(fā)工具類的時(shí)候,工具類方法的類型
*是選擇對(duì)象方法,還是使用靜態(tài)方法
*主要區(qū)分依據(jù),就是看下在方法內(nèi)部是否可以借助 this 對(duì)象中的屬性獲取其他信息
*如果不需要,則統(tǒng)一使用靜態(tài)方法進(jìn)行實(shí)現(xiàn)
*/
$.extend({
'addEvent':function(ele,type,func){
//0.容錯(cuò)處理
if(!$.isDOM(ele) || !$.isString(type) || isFunction(func)){
return;
}
//1.根據(jù)傳遞過來的參數(shù),進(jìn)行事件的監(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ù),進(jìn)行事件的監(jiān)聽
if(ele.removeEventListener){
ele.removeEventListener(type,func);
}else{
ele.detachEvent('on' + type,func);
}
return;
}
});
/*
*13.批量操作事件綁定,和事件解綁的方法
*此處注意開發(fā)步驟
*先從最基本,最小的功能開始左
*比如可以先看下一個(gè) dom 對(duì)象,添加一個(gè)事件類型,綁定一個(gè)回調(diào)函數(shù)的時(shí)候是如何實(shí)現(xiàn)的
*然后慢慢進(jìn)行擴(kuò)展多個(gè)類型的
*多個(gè)回調(diào)函數(shù)的
*多個(gè) DOM 對(duì)象的
*以此類推
*/
$.prototype.extend({
//一個(gè)類型,一個(gè)回調(diào)函數(shù),多個(gè)DOM 對(duì)象的情況
'_on':function(type,func){
//批量給 DOM 對(duì)象,添加事件
this.each(function(index,dom){
$.addEvent(dom,type,func)
})
},
//多個(gè)類型,一個(gè)回調(diào)函數(shù),多個(gè) DOM 對(duì)象的情況
'_on2':function(types,func){
//批量給 DOM 對(duì)象,添加事件
var typeArray = $.trimSpaceArrayWithStr(types);
this.each(function(index,type){
$.each(typeArray,function(index,type){
$.addEvent(dom,type,func)
})
})
},
//多個(gè)類型,多個(gè)回調(diào)函數(shù),多個(gè) DOM 對(duì)象的情況
'_on3':function(firstParam){
//當(dāng)事件綁定的時(shí)候
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 對(duì)象,添加事件
var typeArray = $.trimSpaceArrayWithStr(arguments[0]);
var func = arguments[1];
this.each(function(index.dom){
$.each(typeArray,function(index,type){
$.addEvent(dom,type,func);
})
})
}
},
//為了存儲(chǔ),監(jiān)聽的事件信息,方便解綁
'on':function(firstParam){
//當(dāng)事件綁定的時(shí)候,把這個(gè) DOM 對(duì)象身上的事件類型,和事件回調(diào)都給記錄下來
if(arguments.length === 1){
if(!$.isObject(firstParam)){
return this;
}
this.each(function(index,dom){
//1.給 dom, 新增一個(gè)屬性
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);
})
})
}
},
//解綁多個(gè) DOM 對(duì)象,一個(gè)事件類型的情況
'_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;
},
//解綁多個(gè) DOM 對(duì)象,多個(gè)事件類型的情況
'_off2':function(types){
var typeArr = $.trimSpaceArrayWithStr(types);
this.each(function(index,dom){
$.each(typeArr,function(index,type){
//找到類型對(duì)應(yīng)的回調(diào)函數(shù)組
var funcs = dom['eventCache'][type];
//解綁函數(shù)
$.each(funcs,function(index,func){
$.removeEvent(dom,type,func)
})
})
});
return this;
},
/*
*解綁多個(gè)DOM 對(duì)象,一個(gè)事件類型 指定回調(diào)函數(shù)的情況
*注意:吃出的開發(fā),需要結(jié)合 on 方法內(nèi)部,先記錄下,當(dāng)前對(duì)象綁定的事件信息
*/
'off': function (types, paramFunc) {
// type === 'click'
var typeArr = $.trimSpaceArrayWithStr(types);
// 遍歷所有的DOM對(duì)象
this.each(function (index, dom) {
console.log(dom['eventCache']);
// 遍歷所有的事件類型
$.each(typeArr, function (index, type) {
// 找到類型對(duì)應(yīng)的回調(diào)函數(shù)數(shù)組
var funcs = dom['eventCache'][type];
// 解綁函數(shù)
// 遍歷所有的函數(shù)
$.each(funcs, function (index, func) {
// 處理指定函數(shù)這個(gè)參數(shù)沒有傳遞的情況
if (paramFunc === undefined) {
$.removeEvent(dom, type, func);
}
// 處理指定函數(shù) 這個(gè)參數(shù)傳遞的情況
if (func === paramFunc) {
// 解綁
$.removeEvent(dom, type, func);
}
})
})
});
return this;
}
})
})(window)