jQuery原理
1.来看一下jQuery自己的结构
(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的本质是一个闭包 2.jQuery为什么要使用闭包来实现? 为了避免多个框架的冲突 3.jQuery如何让外界访问内部定义的局部变量 window.xxx = xxx; 4.jQuery为什么要给自己传递一个window参数? 为了方便后期压缩代码,直接将window赋值给一个短的变量 为了提升查找的效率 5.jQuery为什么要给自己接收一个undefined参数? 为了方便后期压缩代码 IE9以下的浏览器undefined可以被修改, 为了保证内部使用的undefined不被修改, 所以需要接收 一个正确的undefined 6.new jQuery.prototype.init( ); 为了在init里访问jQuery里边的方法,将init的原型改为jQuery的原型 */
以上搭建框架的原型图![8D`9TUHYG(N)BB98TDIGQI.png
我们也仿照这个格式来搭建自己的基本结构
(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.入口函数
2.1入口函数测试
<script> window.onload = function (ev) { // $(function () { /* jQ入口函数传入不同参数得到的实例 1.传入 '' null undefined NaN 0 false 2.传入html片段 3.传入选择器 4.传入数组 5.传入伪数组 6.传入对象 7.传入DOM元素 8.传入基本数据类型 */ // 1.传入 '' null undefined NaN 0 false // 会返回一个空的jQuery对象给我们 console.log($()); console.log($('')); console.log($(null)); console.log($(undefined)); console.log($(NaN)); console.log($(0)); console.log($(false)); // 2.传入html片段 // 会将创建好的DOM元素存储到jQuery对象中返回 console.log($('<p>1</p><p>2</p><p>3</p>')); // console.log($(' <div><p>1</p></div><div><p>2</p></div> ')); // 3.传入选择器 // 会将找到的所有元素存储到jQuery对象中返回 console.log($('li')); // 4.传入数组 // 会将数组中存储的元素依次存储到jQuery对象中立返回 var arr = [1, 2, 3, 4, 5, 6]; console.log($(arr)); // 5.传入伪数组 // 会将数组中存储的元素依次存储到jQuery对象中立返回 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.传入对象 // 会将传入的对象存储到jQuery对象中返回 function Person() {} console.log($(new Person())); // 7.传入DOM元素 // 会将传入的DOM元素存储到jQuery对象中返回 console.log($(document.createElement('div'))); // 8.传入基本数据类型 // 会将传入的基本数据类型存储到jQuery对象中返回 console.log($(123)); console.log($(true)); /* 1.传入 '' null undefined NaN 0 false, 返回空的jQuery对象 2.字符串: 代码片段:会将创建好的DOM元素存储到jQuery对象中返回 选择器: 会将找到的所有元素存储到jQuery对象中返回 3.数组: 会将数组中存储的元素依次存储到jQuery对象中立返回 4.除上述类型以外的:6 7 8 会将传入的数据存储到jQuery对象中返回 */ // }); } </script>
先来了解一些方法
2.2 call和apply
<script> /* apply和call方法的作用: 专门用于修改方法内部的this 格式: call(对象, 参数1, 参数2, ...); apply(对象, [数组]); */ function test() { console.log(this); } // window.test(); var obj = {"name": "lnj2"}; /* 1.通过window.test找到test方法 2.通过apply(obj)将找到的test方法内部的this修改为自定义的对象 */ 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.通过window.sum找到sum方法 2.通过apply(obj)将找到的sum方法内部的this修改为自定义的对象 3.将传入数组中的元素依次取出, 传递给形参 */ window.sum.apply(obj, [3, 5]); // 真数组转换伪数组的一个过程 // var arr = [1, 3, 5, 7, 9]; // var obj = {}; /* 1.通过[].push找到数组中的push方法 2.通过apply(obj)将找到的push方法内部的this修改为自定义的对象 3.将传入数组中的元素依次取出, 传递给形参 */ [].push.apply(obj, arr); console.log(obj); window.onload = function (ev) { // 系统自带的伪数组 var res = document.querySelectorAll("div"); // 自定义的伪数组 var obj = {0:"lnj", 1:"33", length: 2}; // var arr = []; // 真数组 // [].push.apply(arr, obj); // console.log(arr); //上面这个方法只能在IE9以上的浏览器用,所以使用 如果想将伪数组转换为真数组那么可以使用如下方法 var arr = [].slice.call(obj); //即将数组的this改为obj,然后通过slice方法什么参数都没有传递,将数组中的元素放到一个新的数组中原样返回 console.log(arr); // var arr2 = [1, 3, 5, 7, 9]; // 如果slice方法什么参数都没有传递, 会将数组中的元素放到一个新的数组中原样返回 // 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, "");//正则表达式 } }
2.4 判断是不是数组
//是数组的话一定是对象,并且具有length属性,并且不是window function(sele){ if(njQuery.isObject(sele) && !njQuery.isWindow(sele) && "length" in sele){ return true; } return false; }
2.5 extend方法
//当我们有很多自定义的函数时,在维护时会很不方便,extend就是为了解决这个问题 function njQuery() { } /* njQuery.extend = function (obj) { // 此时此刻的this就是njQuery这个类 // 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) { // 此时此刻的this是njQuery对象 // 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(); */ //将以上两种合起来写就是下面这样的,既可以添加静态方法,又可以添加实例方法 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事件会等到DOM元素加载完毕, 并且还会等到资源也加载完毕才会执行 DOMContentLoaded事件只会等到DOM元素加载完毕就会执行回调 */ /* 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属性有如下的状态 uninitialized - 还未开始载入 loading - 载入中 interactive - 已加载,文档与用户可以开始交互 complete - 载入完成 onreadystatechange事件就是专门用于监听document.readyState属性的改变的 */ /* 以下是在低版本浏览器中也能用 document.attachEvent("onreadystatechange", function () { if(document.readyState == "complete"){ console.log("onreadystatechange"); } }); */ //综上所述,用来判断的方法就是 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); });
实现以下方法
//jQ原型上的核心方法和属性:
/*
1、jquery 获取jQ版本号
2、selector 实例默认的选择器取值
3、length 实例默认的长度
3、push 给实例添加新元素
4、sort 对实例中的元素进行排序
5、splice 按照指定下标指定数量删除元素,也可以替换删除的元素
6、toArray 把实例转换为数组返回
7、get 获取指定下标的元素,获取的是原生DOM
6、eq 获取指定下标的元素,获取的是jQuery类型的实例对象
7、first 获取实例中的第一个元素,是jQuery类型的实例对象
8、last 获取实例中的最后一个元素,是jQuery类型的实例对象
9、each 遍历实例,把遍历到的数据传给回调使用
10、map 遍历实例,把遍历到的数据传给回调使用,然后把回调的返回值收集起来组成一个新的数组返回
*/
//dom操作相关的方法
/*
1、empty ==> 清空指定元素中的所有内容
2、remove ==> 删除所有的元素或指定元素
3、html ==> 设置所有元素的内容,获取第一个元素的内容
4、text ==> 设置所有元素的文本内容,获取所有元素的文本内容
5、元素.appendTo.指定元素 ==> 将元素添加到指定元素内部的最后
6.元素.prependTo.指定元素 ==> 将元素添加到指定元素内部的最前面
7、指定元素.append.元素 ==> 将元素添加到指定元素内部的最后
8、指定元素.prepend.元素 ==> 将元素添加到指定元素内部的最前面
9.元素.insertBefore.指定元素 ==>将元素添加到指定元素外部的前面
10.next([expr]) 获取紧邻的后面同辈元素的元素
11.prev([expr]) 获取元素紧邻的前一个同辈元素
12.元素.insertAfter.指定元素 ==>将元素添加到指定元素外部的后面
13.指定元素.after.元素 ==>将元素添加到指定元素外部的后面
14.元素.insertBefore.指定元素 ==>将元素添加到指定元素外部的前面
15.指定元素.before.元素 ==>将元素添加到指定元素外部的前面
16、元素.replaceAll.指定元素 ==> 替换所有指定元素
17.指定元素.replaceWith.元素 ==> 替换所有指定元素
*/
//属性操作相关方法
/*
1.attr(): 设置或者获取元素的属性节点值
2.prop(): 设置或者获取元素的属性值
3.css(): 设置获取样式
4.val(): 获取设置value的值
5.hasClass(): 判断元素中是否包含指定类
6.addClass(): 给元素添加一个或多个指定的类
7.removeClass(): 删除元素中一个或多个指定的类
8.toggleClass(): 没有则添加,有则删除
*/
//事件操作相关方法
/*
1.on(type, callback): 注册事件
2.off(type, callback): 移出事件
*/
代码实现
(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对象
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.根据代码片段创建所有的元素
var temp = document.createElement("div");
temp.innerHTML = selector;
// 2.将创建好的一级元素添加到jQuery当中
[].push.apply(this, temp.children);
}
// 2.2判断是否是选择器
else{
// 1.根据传入的选择器找到对应的元素
var res = document.querySelectorAll(selector);
// 2.将找到的元素添加到njQuery上
[].push.apply(this, res);
}
}
// 4.数组
else if(njQuery.isArray(selector)){
// 转换为真数组
var arr = [].slice.call(selector);
// 将真数组数据添加到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) {
// 没有传递参数
if(arguments.length === 0){
return this.toArray();
}
// 传递不是负数
else if(num >= 0){
return this[num];
}
// 传递负数
else{
return this[this.length + num];
}
},
eq: function (num) {
// 没有传递参数
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) {
// 如果已经加载过了, 那么直接调用回调
if(document.readyState == "complete"){
fn();
}
// 如果没有加载过,判断是否支持addEventListener方法, 支持就使用addEventListener方法监听DOM加载
else if(document.addEventListener){
document.addEventListener("DOMContentLoaded", function () {
fn();
});
}
// 如果不支持addEventListener方法, 就使用attachEvent方法监听
else{
document.attachEvent("onreadystatechange", function () {
if(document.readyState == "complete"){
fn();
}
});
}
},
each: function (obj, fn) {
// 1.判断是否是数组
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.判断是否是对象
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.判断是否是数组
if(njQuery.isArray(obj)){
for(var i = 0; i < obj.length; i++){
var temp = fn(obj[i], i);
if(temp){
res.push(temp);
}
}
}
// 2.判断是否是对象
else if(njQuery.isObject(obj)){
for(var key in obj){
var temp =fn(obj[key], key);
if(temp){
res.push(temp);
}
}
}
return res;
},
// 来源: 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操作相关方法
njQuery.prototype.extend({
empty: function () {
// 1.遍历指定的元素
this.each(function (key, value) {
value.innerHTML = "";
});
// 2.方便链式编程
return this;
},
remove: function (sele) {
if(arguments.length === 0){
// 1.遍历指定的元素
this.each(function (key, value) {
// 根据遍历到的元素找到对应的父元素
var parent = value.parentNode;
// 通过父元素删除指定的元素
parent.removeChild(value);
});
}else{
var $this = this;
// 1.根据传入的选择器找到对应的元素
$(sele).each(function (key, value) {
// 2.遍历找到的元素, 获取对应的类型
var type = value.tagName;
// 3.遍历指定的元素
$this.each(function (k, v) {
// 4.获取指定元素的类型
var t = v.tagName;
// 5.判断找到元素的类型和指定元素的类型
if(t === type){
// 根据遍历到的元素找到对应的父元素
var parent = value.parentNode;
// 通过父元素删除指定的元素
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.统一的将传入的数据转换为jQuery对象
var $target = $(sele);
var $this = this;
var res = [];
// 2.遍历取出所有指定的元素
$.each($target, function (key, value) {
// 2.遍历取出所有的元素
$this.each(function (k, v) {
// 3.判断当前是否是第0个指定的元素
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.统一的将传入的数据转换为jQuery对象
var $target = $(sele);
var $this = this;
var res = [];
// 2.遍历取出所有指定的元素
$.each($target, function (key, value) {
// 2.遍历取出所有的元素
$this.each(function (k, v) {
// 3.判断当前是否是第0个指定的元素
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) {
// 判断传入的参数是否是字符串
if(njQuery.isString(sele)){
this[0].innerHTML += sele;
}else{
$(sele).appendTo(this);
}
return this;
},
prepend: function (sele) {
// 判断传入的参数是否是字符串
if(njQuery.isString(sele)){
this[0].innerHTML = sele + this[0].innerHTML;
}else{
$(sele).prependTo(this);
}
return this;
},
insertBefore: function (sele) {
// 1.统一的将传入的数据转换为jQuery对象
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.判断当前是否是第0个指定的元素
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.统一的将传入的数据转换为jQuery对象
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.判断当前是否是第0个指定的元素
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.统一的将传入的数据转换为jQuery对象
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.判断当前是否是第0个指定的元素
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 = [];
// 判断是否是深复制
if(deep){
// 深复制
this.each(function (key, ele) {
var temp = ele.cloneNode(true);
// 遍历元素中的eventsCache对象
njQuery.each(ele.eventsCache, function (name, array) {
// 遍历事件对应的数组
njQuery.each(array, function (index, method) {
// 给复制的元素添加事件
$(temp).on(name, method);
});
});
res.push(temp);
});
return $(res);
}else{
// 浅复制
this.each(function (key, ele) {
var temp = ele.cloneNode(true);
res.push(temp);
});
return $(res);
}
}
});
// 筛选相关方法
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);
}
});
// 属性操作相关的方法
njQuery.prototype.extend({
attr: function (attr, value) {
// 1.判断是否是字符串
if(njQuery.isString(attr)){
// 判断是一个字符串还是两个字符串
if(arguments.length === 1){
return this[0].getAttribute(attr);
}else{
this.each(function (key, ele) {
ele.setAttribute(attr, value);
});
}
}
// 2.判断是否是对象
else if(njQuery.isObject(attr)){
var $this = this;
// 遍历取出所有属性节点的名称和对应的值
$.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)){
// 判断是一个字符串还是两个字符串
if(arguments.length === 1){
return this[0][attr];
}else{
this.each(function (key, ele) {
ele[attr] = value;
});
}
}
// 2.判断是否是对象
else if(njQuery.isObject(attr)){
var $this = this;
// 遍历取出所有属性节点的名称和对应的值
$.each(attr, function (key, value) {
// 遍历取出所有的元素
$this.each(function (k, ele) {
ele[key] = value;
});
});
}
return this;
},
css: function (attr, value) {
// 1.判断是否是字符串
if(njQuery.isString(attr)){
// 判断是一个字符串还是两个字符串
if(arguments.length === 1){
return njQuery.getStyle(this[0], attr);
}else{
this.each(function (key, ele) {
ele.style[attr] = value;
});
}
}
// 2.判断是否是对象
else if(njQuery.isObject(attr)){
var $this = this;
// 遍历取出所有属性节点的名称和对应的值
$.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.通过indexOf判断是否包含指定的字符串
if(className.indexOf(name) != -1){
flag = true;
return false;
}
});
return flag;
}
},
addClass: function (name) {
if(arguments.length === 0) return this;
// 1.对传入的类名进行切割
var names = name.split(" ");
// 2.遍历取出所有的元素
this.each(function (key, ele) {
// 3.遍历数组取出每一个类名
$.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.对传入的类名进行切割
var names = name.split(" ");
// 2.遍历取出所有的元素
this.each(function (key, ele) {
// 3.遍历数组取出每一个类名
$.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.对传入的类名进行切割
var names = name.split(" ");
// 2.遍历取出所有的元素
this.each(function (key, ele) {
// 3.遍历数组取出每一个类名
$.each(names, function (k, value) {
// 4.判断指定元素中是否包含指定的类名
if($(ele).hasClass(value)){
// 删除
$(ele).removeClass(value);
}else{
// 添加
$(ele).addClass(value);
}
});
});
}
return this;
}
});
// 事件操作相关的方法
njQuery.prototype.extend({
on: function (name, callBack) {
// 1.遍历取出所有元素
this.each(function (key, ele) {
// 2.判断当前元素中是否有保存所有事件的对象
if(!ele.eventsCache){
ele.eventsCache = {};
}
// 3.判断对象中有没有对应类型的数组
if(!ele.eventsCache[name]){
ele.eventsCache[name] = [];
// 4.将回调函数添加到数据中
ele.eventsCache[name].push(callBack);
// 5.添加对应类型的事件
njQuery.addEvent(ele, name, function () {
njQuery.each(ele.eventsCache[name], function (k, method) {
method.call(ele);
});
});
}else{
// 6.将回调函数添加到数据中
ele.eventsCache[name].push(callBack);
}
});
return this;
},
off: function (name, callBack) {
// 1.判断是否没有传入参数
if(arguments.length === 0){
this.each(function (key, ele) {
ele.eventsCache = {};
});
}
// 2.判断是否传入了一个参数
else if(arguments.length === 1){
this.each(function (key, ele) {
ele.eventsCache[name] = [];
});
}
// 3.判断是否传入了两个参数
else if(arguments.length === 2){
this.each(function (key, ele) {
njQuery.each(ele.eventsCache[name], function (index, method) {
// 判断当前遍历到的方法和传入的方法是否相同
if(method === callBack){
ele.eventsCache[name].splice(index, 1);
}
});
});
}
return this;
}
});
njQuery.prototype.init.prototype = njQuery.prototype;
window.njQuery = window.$ = njQuery;
})( window );