jQuery原理
1.來(lái)看一下jQuery自己的結(jié)構(gòu)
(function( window, undefined ) { var jQuery = function( ) { return new jQuery.prototype.init( ); } jQuery.prototype = { constructor: jQuery, init:function(){} } jQuery.prototype.init.prototype = jQuery.prototype; window.jQuery = window.$ = jQuery; })( window ); /* 1.jQuery的本質(zhì)是一個(gè)閉包 2.jQuery為什么要使用閉包來(lái)實(shí)現(xiàn)? 為了避免多個(gè)框架的沖突 3.jQuery如何讓外界訪問(wèn)內(nèi)部定義的局部變量 window.xxx = xxx; 4.jQuery為什么要給自己傳遞一個(gè)window參數(shù)? 為了方便后期壓縮代碼,直接將window賦值給一個(gè)短的變量 為了提升查找的效率 5.jQuery為什么要給自己接收一個(gè)undefined參數(shù)? 為了方便后期壓縮代碼 IE9以下的瀏覽器undefined可以被修改, 為了保證內(nèi)部使用的undefined不被修改, 所以需要接收 一個(gè)正確的undefined 6.new jQuery.prototype.init( ); 為了在init里訪問(wèn)jQuery里邊的方法,將init的原型改為jQuery的原型 */
以上搭建框架的原型圖![8D`9TUHYG(N)BB98TDIGQI.png
我們也仿照這個(gè)格式來(lái)搭建自己的基本結(jié)構(gòu)
(function( window, undefined ) { var njQuery = function( ) { return new njQuery.prototype.init( ); } njQuery.prototype = { constructor: njQuery } njQuery.prototype.init.prototype = njQuery.prototype; window.njQuery = window.$ = njQuery; })( window );
2.入口函數(shù)
2.1入口函數(shù)測(cè)試
<script> window.onload = function (ev) { // $(function () { /* jQ入口函數(shù)傳入不同參數(shù)得到的實(shí)例 1.傳入 '' null undefined NaN 0 false 2.傳入html片段 3.傳入選擇器 4.傳入數(shù)組 5.傳入偽數(shù)組 6.傳入對(duì)象 7.傳入DOM元素 8.傳入基本數(shù)據(jù)類型 */ // 1.傳入 '' null undefined NaN 0 false // 會(huì)返回一個(gè)空的jQuery對(duì)象給我們 console.log($()); console.log($('')); console.log($(null)); console.log($(undefined)); console.log($(NaN)); console.log($(0)); console.log($(false)); // 2.傳入html片段 // 會(huì)將創(chuàng)建好的DOM元素存儲(chǔ)到j(luò)Query對(duì)象中返回 console.log($('<p>1</p><p>2</p><p>3</p>')); // console.log($(' <div><p>1</p></div><div><p>2</p></div> ')); // 3.傳入選擇器 // 會(huì)將找到的所有元素存儲(chǔ)到j(luò)Query對(duì)象中返回 console.log($('li')); // 4.傳入數(shù)組 // 會(huì)將數(shù)組中存儲(chǔ)的元素依次存儲(chǔ)到j(luò)Query對(duì)象中立返回 var arr = [1, 2, 3, 4, 5, 6]; console.log($(arr)); // 5.傳入偽數(shù)組 // 會(huì)將數(shù)組中存儲(chǔ)的元素依次存儲(chǔ)到j(luò)Query對(duì)象中立返回 var likeArr = {0:"lnj", 1:"33", 2:"male", length: 3}; console.log($(likeArr)); // console.log(typeof arr); // console.log(typeof likeArr); // console.log(arr.toString()); // console.log(likeArr.toString()); // console.log(({}).toString.apply(arr)); // 6.傳入對(duì)象 // 會(huì)將傳入的對(duì)象存儲(chǔ)到j(luò)Query對(duì)象中返回 function Person() {} console.log($(new Person())); // 7.傳入DOM元素 // 會(huì)將傳入的DOM元素存儲(chǔ)到j(luò)Query對(duì)象中返回 console.log($(document.createElement('div'))); // 8.傳入基本數(shù)據(jù)類型 // 會(huì)將傳入的基本數(shù)據(jù)類型存儲(chǔ)到j(luò)Query對(duì)象中返回 console.log($(123)); console.log($(true)); /* 1.傳入 '' null undefined NaN 0 false, 返回空的jQuery對(duì)象 2.字符串: 代碼片段:會(huì)將創(chuàng)建好的DOM元素存儲(chǔ)到j(luò)Query對(duì)象中返回 選擇器: 會(huì)將找到的所有元素存儲(chǔ)到j(luò)Query對(duì)象中返回 3.數(shù)組: 會(huì)將數(shù)組中存儲(chǔ)的元素依次存儲(chǔ)到j(luò)Query對(duì)象中立返回 4.除上述類型以外的:6 7 8 會(huì)將傳入的數(shù)據(jù)存儲(chǔ)到j(luò)Query對(duì)象中返回 */ // }); } </script>
先來(lái)了解一些方法
2.2 call和apply
<script> /* apply和call方法的作用: 專門用于修改方法內(nèi)部的this 格式: call(對(duì)象, 參數(shù)1, 參數(shù)2, ...); apply(對(duì)象, [數(shù)組]); */ function test() { console.log(this); } // window.test(); var obj = {"name": "lnj2"}; /* 1.通過(guò)window.test找到test方法 2.通過(guò)apply(obj)將找到的test方法內(nèi)部的this修改為自定義的對(duì)象 */ window.test.apply(obj); window.test.call(obj); function sum(a, b) { console.log(this); console.log(a + b); } // window.sum.call(obj, 1, 2); /* 1.通過(guò)window.sum找到sum方法 2.通過(guò)apply(obj)將找到的sum方法內(nèi)部的this修改為自定義的對(duì)象 3.將傳入數(shù)組中的元素依次取出, 傳遞給形參 */ window.sum.apply(obj, [3, 5]); // 真數(shù)組轉(zhuǎn)換偽數(shù)組的一個(gè)過(guò)程 // var arr = [1, 3, 5, 7, 9]; // var obj = {}; /* 1.通過(guò)[].push找到數(shù)組中的push方法 2.通過(guò)apply(obj)將找到的push方法內(nèi)部的this修改為自定義的對(duì)象 3.將傳入數(shù)組中的元素依次取出, 傳遞給形參 */ [].push.apply(obj, arr); console.log(obj); window.onload = function (ev) { // 系統(tǒng)自帶的偽數(shù)組 var res = document.querySelectorAll("div"); // 自定義的偽數(shù)組 var obj = {0:"lnj", 1:"33", length: 2}; // var arr = []; // 真數(shù)組 // [].push.apply(arr, obj); // console.log(arr); //上面這個(gè)方法只能在IE9以上的瀏覽器用,所以使用 如果想將偽數(shù)組轉(zhuǎn)換為真數(shù)組那么可以使用如下方法 var arr = [].slice.call(obj); //即將數(shù)組的this改為obj,然后通過(guò)slice方法什么參數(shù)都沒(méi)有傳遞,將數(shù)組中的元素放到一個(gè)新的數(shù)組中原樣返回 console.log(arr); // var arr2 = [1, 3, 5, 7, 9]; // 如果slice方法什么參數(shù)都沒(méi)有傳遞, 會(huì)將數(shù)組中的元素放到一個(gè)新的數(shù)組中原樣返回 // var res2 = arr2.slice(); // var res2 = arr2.slice(2); // var res2 = arr2.slice(2, 4); // console.log(res2); } </script>
2.3 去除傳入字符串兩邊的空格
function(str){ if(!njQuery.isString(str)){ return str; } // 判斷是否支持trim方法 高版本瀏覽器 if(str.trim){ return str.trim(); }else{ return str.replace(/^\s+|\s+$/g, "");//正則表達(dá)式 } }
2.4 判斷是不是數(shù)組
//是數(shù)組的話一定是對(duì)象,并且具有l(wèi)ength屬性,并且不是window function(sele){ if(njQuery.isObject(sele) && !njQuery.isWindow(sele) && "length" in sele){ return true; } return false; }
2.5 extend方法
//當(dāng)我們有很多自定義的函數(shù)時(shí),在維護(hù)時(shí)會(huì)很不方便,extend就是為了解決這個(gè)問(wèn)題 function njQuery() { } /* njQuery.extend = function (obj) { // 此時(shí)此刻的this就是njQuery這個(gè)類 // console.log(this); for(var key in obj){ // njQuery["isTest"] = function () {console.log("test");} this[key] = obj[key]; } } njQuery.extend({ isTest: function () { console.log("test"); } }); njQuery.isTest(); */ /* njQuery.prototype.extend = function (obj) { // 此時(shí)此刻的this是njQuery對(duì)象 // console.log(this); for(var key in obj){ // q["isDemo"] = function () {console.log("demo");} this[key] = obj[key]; } } var q = new njQuery(); q.extend({ isDemo: function () { console.log("demo"); } }); q.isDemo(); */ //將以上兩種合起來(lái)寫就是下面這樣的,既可以添加靜態(tài)方法,又可以添加實(shí)例方法 njQuery.extend = njQuery.prototype.extend = function (obj) { //console.log(this); for(var key in obj){ this[key] = obj[key]; } } njQuery.extend({}); var q = new njQuery(); q.extend();
2.6判斷dom元素是否加載完畢
/* onload事件會(huì)等到DOM元素加載完畢, 并且還會(huì)等到資源也加載完畢才會(huì)執(zhí)行 DOMContentLoaded事件只會(huì)等到DOM元素加載完畢就會(huì)執(zhí)行回調(diào) */ /* window.onload = function (ev) { // var res = document.querySelectorAll("div"); // console.log(res); console.log("onload"); } document.addEventListener("DOMContentLoaded", function () { // var res = document.querySelectorAll("div"); // console.log(res); console.log("DOMContentLoaded"); }); 但是低版本的瀏覽器不支持addEventListene */ /* document.readyState屬性有如下的狀態(tài) uninitialized - 還未開(kāi)始載入 loading - 載入中 interactive - 已加載,文檔與用戶可以開(kāi)始交互 complete - 載入完成 onreadystatechange事件就是專門用于監(jiān)聽(tīng)document.readyState屬性的改變的 */ /* 以下是在低版本瀏覽器中也能用 document.attachEvent("onreadystatechange", function () { if(document.readyState == "complete"){ console.log("onreadystatechange"); } }); */ //綜上所述,用來(lái)判斷的方法就是 if(document.addEventListener){ document.addEventListener("DOMContentLoaded", function () { fn(); }); }else{ document.attachEvent("onreadystatechange", function () { if(document.readyState == "complete"){ fn(); } }); } $(function () { var res = document.querySelectorAll("div"); console.log(res); });
實(shí)現(xiàn)以下方法
//jQ原型上的核心方法和屬性:
/*
1、jquery 獲取jQ版本號(hào)
2、selector 實(shí)例默認(rèn)的選擇器取值
3、length 實(shí)例默認(rèn)的長(zhǎng)度
3、push 給實(shí)例添加新元素
4、sort 對(duì)實(shí)例中的元素進(jìn)行排序
5、splice 按照指定下標(biāo)指定數(shù)量刪除元素,也可以替換刪除的元素
6、toArray 把實(shí)例轉(zhuǎn)換為數(shù)組返回
7、get 獲取指定下標(biāo)的元素,獲取的是原生DOM
6、eq 獲取指定下標(biāo)的元素,獲取的是jQuery類型的實(shí)例對(duì)象
7、first 獲取實(shí)例中的第一個(gè)元素,是jQuery類型的實(shí)例對(duì)象
8、last 獲取實(shí)例中的最后一個(gè)元素,是jQuery類型的實(shí)例對(duì)象
9、each 遍歷實(shí)例,把遍歷到的數(shù)據(jù)傳給回調(diào)使用
10、map 遍歷實(shí)例,把遍歷到的數(shù)據(jù)傳給回調(diào)使用,然后把回調(diào)的返回值收集起來(lái)組成一個(gè)新的數(shù)組返回
*/
//dom操作相關(guān)的方法
/*
1、empty ==> 清空指定元素中的所有內(nèi)容
2、remove ==> 刪除所有的元素或指定元素
3、html ==> 設(shè)置所有元素的內(nèi)容,獲取第一個(gè)元素的內(nèi)容
4、text ==> 設(shè)置所有元素的文本內(nèi)容,獲取所有元素的文本內(nèi)容
5、元素.appendTo.指定元素 ==> 將元素添加到指定元素內(nèi)部的最后
6.元素.prependTo.指定元素 ==> 將元素添加到指定元素內(nèi)部的最前面
7、指定元素.append.元素 ==> 將元素添加到指定元素內(nèi)部的最后
8、指定元素.prepend.元素 ==> 將元素添加到指定元素內(nèi)部的最前面
9.元素.insertBefore.指定元素 ==>將元素添加到指定元素外部的前面
10.next([expr]) 獲取緊鄰的后面同輩元素的元素
11.prev([expr]) 獲取元素緊鄰的前一個(gè)同輩元素
12.元素.insertAfter.指定元素 ==>將元素添加到指定元素外部的后面
13.指定元素.after.元素 ==>將元素添加到指定元素外部的后面
14.元素.insertBefore.指定元素 ==>將元素添加到指定元素外部的前面
15.指定元素.before.元素 ==>將元素添加到指定元素外部的前面
16、元素.replaceAll.指定元素 ==> 替換所有指定元素
17.指定元素.replaceWith.元素 ==> 替換所有指定元素
*/
//屬性操作相關(guān)方法
/*
1.attr(): 設(shè)置或者獲取元素的屬性節(jié)點(diǎn)值
2.prop(): 設(shè)置或者獲取元素的屬性值
3.css(): 設(shè)置獲取樣式
4.val(): 獲取設(shè)置value的值
5.hasClass(): 判斷元素中是否包含指定類
6.addClass(): 給元素添加一個(gè)或多個(gè)指定的類
7.removeClass(): 刪除元素中一個(gè)或多個(gè)指定的類
8.toggleClass(): 沒(méi)有則添加,有則刪除
*/
//事件操作相關(guān)方法
/*
1.on(type, callback): 注冊(cè)事件
2.off(type, callback): 移出事件
*/
代碼實(shí)現(xiàn)
(function( window, undefined ) {
var njQuery = function(selector) {
return new njQuery.prototype.init(selector);
}
njQuery.prototype = {
constructor: njQuery,
init: function (selector) {
// 0.去除字符串兩端的空格
selector = njQuery.trim(selector);
// 1.傳入 '' null undefined NaN 0 false, 返回空的jQuery對(duì)象
if(!selector){
return this;
}
// 2.方法處理
else if(njQuery.isFunction(selector)){
njQuery.ready(selector);
}
// 3.字符串
else if(njQuery.isString(selector)){
// 2.1判斷是否是代碼片段 <a>
if(njQuery.isHTML(selector)){
// 1.根據(jù)代碼片段創(chuàng)建所有的元素
var temp = document.createElement("div");
temp.innerHTML = selector;
// 2.將創(chuàng)建好的一級(jí)元素添加到j(luò)Query當(dāng)中
[].push.apply(this, temp.children);
}
// 2.2判斷是否是選擇器
else{
// 1.根據(jù)傳入的選擇器找到對(duì)應(yīng)的元素
var res = document.querySelectorAll(selector);
// 2.將找到的元素添加到njQuery上
[].push.apply(this, res);
}
}
// 4.數(shù)組
else if(njQuery.isArray(selector)){
// 轉(zhuǎn)換為真數(shù)組
var arr = [].slice.call(selector);
// 將真數(shù)組數(shù)據(jù)添加到njQuery上
[].push.apply(this, arr);
}
// 5.除上述類型以外
else{
this[0] = selector;
this.length = 1;
}
// 返回njQuery
return this;
},
jquery: "1.1.0",
selector: "",
length: 0,
push: [].push,
sort: [].sort,
splice: [].splice,
toArray: function () {
return [].slice.call(this);
},
get: function (num) {
// 沒(méi)有傳遞參數(shù)
if(arguments.length === 0){
return this.toArray();
}
// 傳遞不是負(fù)數(shù)
else if(num >= 0){
return this[num];
}
// 傳遞負(fù)數(shù)
else{
return this[this.length + num];
}
},
eq: function (num) {
// 沒(méi)有傳遞參數(shù)
if(arguments.length === 0){
return new njQuery();
}else{
return njQuery(this.get(num));
}
},
first: function () {
return this.eq(0);
},
last: function () {
return this.eq(-1);
},
each: function (fn) {
return njQuery.each(this, fn);
}
}
njQuery.extend = njQuery.prototype.extend = function (obj) {
for(var key in obj){
this[key] = obj[key];
}
}
// 工具方法
njQuery.extend({
isString : function(str){
return typeof str === "string"
},
isHTML : function(str){
return str.charAt(0) === "<" &&
str.charAt(str.length - 1) === ">" &&
str.length >= 3;
},
trim : function(str){
if(!njQuery.isString(str)){
return str;
}
// 判斷是否支持trim方法
if(str.trim){
return str.trim();
}else{
return str.replace(/^\s+|\s+$/g, "");
}
},
isObject : function(sele){
return typeof sele === "object"
},
isWindow : function(sele){
return sele === window;
},
isArray : function(sele){
if(njQuery.isObject(sele) &&
!njQuery.isWindow(sele) &&
"length" in sele){
return true;
}
return false;
},
isFunction : function(sele){
return typeof sele === "function";
},
ready: function (fn) {
// 如果已經(jīng)加載過(guò)了, 那么直接調(diào)用回調(diào)
if(document.readyState == "complete"){
fn();
}
// 如果沒(méi)有加載過(guò),判斷是否支持addEventListener方法, 支持就使用addEventListener方法監(jiān)聽(tīng)DOM加載
else if(document.addEventListener){
document.addEventListener("DOMContentLoaded", function () {
fn();
});
}
// 如果不支持addEventListener方法, 就使用attachEvent方法監(jiān)聽(tīng)
else{
document.attachEvent("onreadystatechange", function () {
if(document.readyState == "complete"){
fn();
}
});
}
},
each: function (obj, fn) {
// 1.判斷是否是數(shù)組
if(njQuery.isArray(obj)){
for(var i = 0; i < obj.length; i++){
// var res = fn(i, obj[i]);
var res = fn.call(obj[i], i, obj[i]);
if(res === true){
continue;
}else if(res === false){
break;
}
}
}
// 2.判斷是否是對(duì)象
else if(njQuery.isObject(obj)){
for(var key in obj){
// var res = fn(key, obj[key]);
var res = fn.call(obj[key], key, obj[key]);
if(res === true){
continue;
}else if(res === false){
break;
}
}
}
return obj;
},
map: function (obj, fn) {
var res = [];
// 1.判斷是否是數(shù)組
if(njQuery.isArray(obj)){
for(var i = 0; i < obj.length; i++){
var temp = fn(obj[i], i);
if(temp){
res.push(temp);
}
}
}
// 2.判斷是否是對(duì)象
else if(njQuery.isObject(obj)){
for(var key in obj){
var temp =fn(obj[key], key);
if(temp){
res.push(temp);
}
}
}
return res;
},
// 來(lái)源: http://www.w3school.com.cn/xmldom/prop_node_nextsibling.asp
get_nextsibling: function (n) {
var x = n.nextSibling;
while (x != null && x.nodeType!=1)
{
x=x.nextSibling;
}
return x;
},
get_previoussibling: function (n) {
var x=n.previousSibling;
while (x != null && x.nodeType!=1)
{
x=x.previousSibling;
}
return x;
},
getStyle: function (dom, styleName) {
if(window.getComputedStyle){
return window.getComputedStyle(dom)[styleName];
}else{
return dom.currentStyle[styleName];
}
},
addEvent: function(dom, name, callBack) {
if(dom.addEventListener){
dom.addEventListener(name, callBack);
}else{
dom.attachEvent("on"+name, callBack);
}
}
});
// DOM操作相關(guān)方法
njQuery.prototype.extend({
empty: function () {
// 1.遍歷指定的元素
this.each(function (key, value) {
value.innerHTML = "";
});
// 2.方便鏈?zhǔn)骄幊? return this;
},
remove: function (sele) {
if(arguments.length === 0){
// 1.遍歷指定的元素
this.each(function (key, value) {
// 根據(jù)遍歷到的元素找到對(duì)應(yīng)的父元素
var parent = value.parentNode;
// 通過(guò)父元素刪除指定的元素
parent.removeChild(value);
});
}else{
var $this = this;
// 1.根據(jù)傳入的選擇器找到對(duì)應(yīng)的元素
$(sele).each(function (key, value) {
// 2.遍歷找到的元素, 獲取對(duì)應(yīng)的類型
var type = value.tagName;
// 3.遍歷指定的元素
$this.each(function (k, v) {
// 4.獲取指定元素的類型
var t = v.tagName;
// 5.判斷找到元素的類型和指定元素的類型
if(t === type){
// 根據(jù)遍歷到的元素找到對(duì)應(yīng)的父元素
var parent = value.parentNode;
// 通過(guò)父元素刪除指定的元素
parent.removeChild(value);
}
});
})
}
return this;
},
html: function (content) {
if(arguments.length === 0){
return this[0].innerHTML;
}else{
this.each(function (key, value) {
value.innerHTML = content;
})
}
},
text: function (content) {
if(arguments.length === 0){
var res = "";
this.each(function (key, value) {
res += value.innerText;
});
return res;
}else{
this.each(function (key, value) {
value.innerText = content;
});
}
},
appendTo: function (sele) {
// 1.統(tǒng)一的將傳入的數(shù)據(jù)轉(zhuǎn)換為jQuery對(duì)象
var $target = $(sele);
var $this = this;
var res = [];
// 2.遍歷取出所有指定的元素
$.each($target, function (key, value) {
// 2.遍歷取出所有的元素
$this.each(function (k, v) {
// 3.判斷當(dāng)前是否是第0個(gè)指定的元素
if(key === 0){
// 直接添加
value.appendChild(v);
res.push(v);
}else{
// 先拷貝再添加
var temp = v.cloneNode(true);
value.appendChild(temp);
res.push(temp);
}
});
});
// 3.返回所有添加的元素
return $(res);
},
prependTo: function (sele) {
// 1.統(tǒng)一的將傳入的數(shù)據(jù)轉(zhuǎn)換為jQuery對(duì)象
var $target = $(sele);
var $this = this;
var res = [];
// 2.遍歷取出所有指定的元素
$.each($target, function (key, value) {
// 2.遍歷取出所有的元素
$this.each(function (k, v) {
// 3.判斷當(dāng)前是否是第0個(gè)指定的元素
if(key === 0){
// 直接添加
value.insertBefore(v, value.firstChild);
res.push(v);
}else{
// 先拷貝再添加
var temp = v.cloneNode(true);
value.insertBefore(temp, value.firstChild);
res.push(temp);
}
});
});
// 3.返回所有添加的元素
return $(res);
},
append: function (sele) {
// 判斷傳入的參數(shù)是否是字符串
if(njQuery.isString(sele)){
this[0].innerHTML += sele;
}else{
$(sele).appendTo(this);
}
return this;
},
prepend: function (sele) {
// 判斷傳入的參數(shù)是否是字符串
if(njQuery.isString(sele)){
this[0].innerHTML = sele + this[0].innerHTML;
}else{
$(sele).prependTo(this);
}
return this;
},
insertBefore: function (sele) {
// 1.統(tǒng)一的將傳入的數(shù)據(jù)轉(zhuǎn)換為jQuery對(duì)象
var $target = $(sele);
var $this = this;
var res = [];
// 2.遍歷取出所有指定的元素
$.each($target, function (key, value) {
var parent = value.parentNode;
// 2.遍歷取出所有的元素
$this.each(function (k, v) {
// 3.判斷當(dāng)前是否是第0個(gè)指定的元素
if(key === 0){
// 直接添加
parent.insertBefore(v, value);
res.push(v);
}else{
// 先拷貝再添加
var temp = v.cloneNode(true);
parent.insertBefore(temp, value);
res.push(temp);
}
});
});
// 3.返回所有添加的元素
return $(res);
},
insertAfter: function (sele) {
// 1.統(tǒng)一的將傳入的數(shù)據(jù)轉(zhuǎn)換為jQuery對(duì)象
var $target = $(sele);
var $this = this;
var res = [];
// 2.遍歷取出所有指定的元素
$.each($target, function (key, value) {
var parent = value.parentNode;
var nextNode = $.get_nextsibling(value);
// 2.遍歷取出所有的元素
$this.each(function (k, v) {
// 3.判斷當(dāng)前是否是第0個(gè)指定的元素
if(key === 0){
// 直接添加
parent.insertBefore(v, nextNode);
res.push(v);
}else{
// 先拷貝再添加
var temp = v.cloneNode(true);
parent.insertBefore(temp, nextNode);
res.push(temp);
}
});
});
// 3.返回所有添加的元素
return $(res);
},
replaceAll: function (sele) {
// 1.統(tǒng)一的將傳入的數(shù)據(jù)轉(zhuǎn)換為jQuery對(duì)象
var $target = $(sele);
var $this = this;
var res = [];
// 2.遍歷取出所有指定的元素
$.each($target, function (key, value) {
var parent = value.parentNode;
// 2.遍歷取出所有的元素
$this.each(function (k, v) {
// 3.判斷當(dāng)前是否是第0個(gè)指定的元素
if(key === 0){
// 1.將元素插入到指定元素的前面
$(v).insertBefore(value);
// 2.將指定元素刪除
$(value).remove();
res.push(v);
}else{
// 先拷貝再添加
var temp = v.cloneNode(true);
// 1.將元素插入到指定元素的前面
$(temp).insertBefore(value);
// 2.將指定元素刪除
$(value).remove();
res.push(temp);
}
});
});
// 3.返回所有添加的元素
return $(res);
},
clone: function (deep) {
var res = [];
// 判斷是否是深復(fù)制
if(deep){
// 深復(fù)制
this.each(function (key, ele) {
var temp = ele.cloneNode(true);
// 遍歷元素中的eventsCache對(duì)象
njQuery.each(ele.eventsCache, function (name, array) {
// 遍歷事件對(duì)應(yīng)的數(shù)組
njQuery.each(array, function (index, method) {
// 給復(fù)制的元素添加事件
$(temp).on(name, method);
});
});
res.push(temp);
});
return $(res);
}else{
// 淺復(fù)制
this.each(function (key, ele) {
var temp = ele.cloneNode(true);
res.push(temp);
});
return $(res);
}
}
});
// 篩選相關(guān)方法
njQuery.prototype.extend({
next: function (sele) {
var res = [];
if(arguments.length === 0){
// 返回所有找到的
this.each(function (key, value) {
var temp = njQuery.get_nextsibling(value);
if(temp != null){
res.push(temp);
}
});
}else{
// 返回指定找到的
this.each(function (key, value) {
var temp = njQuery.get_nextsibling(value)
$(sele).each(function (k, v) {
if(v == null || v !== temp) return true;
res.push(v);
});
});
}
return $(res);
},
prev: function (sele) {
var res = [];
if(arguments.length === 0){
this.each(function (key, value) {
var temp = njQuery.get_previoussibling(value);
if(temp == null) return true;
res.push(temp);
});
}else{
this.each(function (key, value) {
var temp = njQuery.get_previoussibling(value);
$(sele).each(function (k, v) {
if(v == null || temp !== v) return true;
res.push(v);
})
});
}
return $(res);
}
});
// 屬性操作相關(guān)的方法
njQuery.prototype.extend({
attr: function (attr, value) {
// 1.判斷是否是字符串
if(njQuery.isString(attr)){
// 判斷是一個(gè)字符串還是兩個(gè)字符串
if(arguments.length === 1){
return this[0].getAttribute(attr);
}else{
this.each(function (key, ele) {
ele.setAttribute(attr, value);
});
}
}
// 2.判斷是否是對(duì)象
else if(njQuery.isObject(attr)){
var $this = this;
// 遍歷取出所有屬性節(jié)點(diǎn)的名稱和對(duì)應(yīng)的值
$.each(attr, function (key, value) {
// 遍歷取出所有的元素
$this.each(function (k, ele) {
ele.setAttribute(key, value);
});
});
}
return this;
},
prop: function (attr, value) {
// 1.判斷是否是字符串
if(njQuery.isString(attr)){
// 判斷是一個(gè)字符串還是兩個(gè)字符串
if(arguments.length === 1){
return this[0][attr];
}else{
this.each(function (key, ele) {
ele[attr] = value;
});
}
}
// 2.判斷是否是對(duì)象
else if(njQuery.isObject(attr)){
var $this = this;
// 遍歷取出所有屬性節(jié)點(diǎn)的名稱和對(duì)應(yīng)的值
$.each(attr, function (key, value) {
// 遍歷取出所有的元素
$this.each(function (k, ele) {
ele[key] = value;
});
});
}
return this;
},
css: function (attr, value) {
// 1.判斷是否是字符串
if(njQuery.isString(attr)){
// 判斷是一個(gè)字符串還是兩個(gè)字符串
if(arguments.length === 1){
return njQuery.getStyle(this[0], attr);
}else{
this.each(function (key, ele) {
ele.style[attr] = value;
});
}
}
// 2.判斷是否是對(duì)象
else if(njQuery.isObject(attr)){
var $this = this;
// 遍歷取出所有屬性節(jié)點(diǎn)的名稱和對(duì)應(yīng)的值
$.each(attr, function (key, value) {
// 遍歷取出所有的元素
$this.each(function (k, ele) {
ele.style[key] = value;
});
});
}
return this;
},
val: function (content) {
if(arguments.length === 0){
return this[0].value;
}else{
this.each(function (key, ele) {
ele.value = content;
});
return this;
}
},
hasClass: function (name) {
var flag = false;
if(arguments.length === 0){
return flag;
}else{
this.each(function (key, ele) {
// 1.獲取元素中class保存的值
var className = " "+ele.className+" ";
// 2.給指定字符串的前后也加上空格
name = " "+name+" ";
// 3.通過(guò)indexOf判斷是否包含指定的字符串
if(className.indexOf(name) != -1){
flag = true;
return false;
}
});
return flag;
}
},
addClass: function (name) {
if(arguments.length === 0) return this;
// 1.對(duì)傳入的類名進(jìn)行切割
var names = name.split(" ");
// 2.遍歷取出所有的元素
this.each(function (key, ele) {
// 3.遍歷數(shù)組取出每一個(gè)類名
$.each(names, function (k, value) {
// 4.判斷指定元素中是否包含指定的類名
if(!$(ele).hasClass(value)){
ele.className = ele.className + " " + value;
}
});
});
return this;
},
removeClass: function (name) {
if(arguments.length === 0){
this.each(function (key, ele) {
ele.className = "";
});
}else{
// 1.對(duì)傳入的類名進(jìn)行切割
var names = name.split(" ");
// 2.遍歷取出所有的元素
this.each(function (key, ele) {
// 3.遍歷數(shù)組取出每一個(gè)類名
$.each(names, function (k, value) {
// 4.判斷指定元素中是否包含指定的類名
if($(ele).hasClass(value)){
ele.className = (" "+ele.className+" ").replace(" "+value+" ", "");
}
});
});
}
return this;
},
toggleClass: function (name) {
if(arguments.length === 0){
this.removeClass();
}else{
// 1.對(duì)傳入的類名進(jìn)行切割
var names = name.split(" ");
// 2.遍歷取出所有的元素
this.each(function (key, ele) {
// 3.遍歷數(shù)組取出每一個(gè)類名
$.each(names, function (k, value) {
// 4.判斷指定元素中是否包含指定的類名
if($(ele).hasClass(value)){
// 刪除
$(ele).removeClass(value);
}else{
// 添加
$(ele).addClass(value);
}
});
});
}
return this;
}
});
// 事件操作相關(guān)的方法
njQuery.prototype.extend({
on: function (name, callBack) {
// 1.遍歷取出所有元素
this.each(function (key, ele) {
// 2.判斷當(dāng)前元素中是否有保存所有事件的對(duì)象
if(!ele.eventsCache){
ele.eventsCache = {};
}
// 3.判斷對(duì)象中有沒(méi)有對(duì)應(yīng)類型的數(shù)組
if(!ele.eventsCache[name]){
ele.eventsCache[name] = [];
// 4.將回調(diào)函數(shù)添加到數(shù)據(jù)中
ele.eventsCache[name].push(callBack);
// 5.添加對(duì)應(yīng)類型的事件
njQuery.addEvent(ele, name, function () {
njQuery.each(ele.eventsCache[name], function (k, method) {
method.call(ele);
});
});
}else{
// 6.將回調(diào)函數(shù)添加到數(shù)據(jù)中
ele.eventsCache[name].push(callBack);
}
});
return this;
},
off: function (name, callBack) {
// 1.判斷是否沒(méi)有傳入?yún)?shù)
if(arguments.length === 0){
this.each(function (key, ele) {
ele.eventsCache = {};
});
}
// 2.判斷是否傳入了一個(gè)參數(shù)
else if(arguments.length === 1){
this.each(function (key, ele) {
ele.eventsCache[name] = [];
});
}
// 3.判斷是否傳入了兩個(gè)參數(shù)
else if(arguments.length === 2){
this.each(function (key, ele) {
njQuery.each(ele.eventsCache[name], function (index, method) {
// 判斷當(dāng)前遍歷到的方法和傳入的方法是否相同
if(method === callBack){
ele.eventsCache[name].splice(index, 1);
}
});
});
}
return this;
}
});
njQuery.prototype.init.prototype = njQuery.prototype;
window.njQuery = window.$ = njQuery;
})( window );