jQuery原理笔记

1. jQuery基本结构

  • jQuery本质——闭包
    • 实际上就是一个立即执行的函数
(function( window, undefined ) {
            
})( window );
  • jQuery为何使用闭包实现?
    • 为了避免导入多个框架的时候,变量名重覆盖的问题
(function f1(){
	var num = 10;
	console.log(num);
})(window);

(function f2(){
	var num = 20;
	console.log(num);
})(window);
  • jQuery如何让外界访问内部定义的局部变量?
    • window.xxx = xxx;
/*
(function f1(){
	var num = 10;
	window.num = num;
})();
console.log(num);
*/

(function( window, undefined ) {
    var jQuery = function( ) {
        return new jQuery.prototype.init( );
    }
    
    window.jQuery = window.$ = jQuery;
})( window );
  • jQuery为什么要给自己传递一个window参数?

    • 为了方便后期压缩代码
    • 为了提升查找的效率
  • jQuery为什么要给自己接收一个undefined参数?

    • 为了方便后期压缩代码
    • IE9以下的浏览器undefined可以被修改, 为了保证内部使用的undefined不被修改, 所以需要接收一个正确的undefined

自定义jQuery框架

// 基本结构
(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. jQuery入口函数

1. jQuery入口函数——测试

jQuery入口函数传入不同参数得到的实例

  • 传入 ’ ’ 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));
  • 传入html片段
    • 会将创建好的DOM元素存储到jQuery对象中返回
console.log($('<p>1</p><p>2</p><p>3</p>'));
  • 传入选择器
    • 会将找到的所有元素存储到jQuery对象中返回
console.log($('li'));
  • 传入数组
    • 会将数组中存储的元素依次存储到jQuery对象中立返回
var arr = [1, 2, 3, 4, 5, 6];
console.log($(arr));
  • 传入伪数组
    • 会将数组中存储的元素依次存储到jQuery对象中立返回
var likeArr = {0:"lnj", 1:"33", 2:"male", length: 3};
console.log($(likeArr));
  • 传入对象
    • 会将传入的对象存储到jQuery对象中返回
function Person() {}
console.log($(new Person()));
  • 传入DOM元素
    • 会将传入的DOM元素存储到jQuery对象中返回
console.log($(document.createElement('div')));
  • 传入基本数据类型
    • 会将传入的基本数据类型存储到jQuery对象中返回
console.log($(123));
console.log($(true));
  • 除上述类型以外
    • 会将传入的数据存储到jQuery对象中返回

2. jQuery入口函数——代码片段实现

// 基本结构
(function(window,undefined){
	var njQuery = function(selector){
		return new njQuery.prototype.init(selector);
	}
	njQuery.prototype = {
		constructor:njQuery,
		init:function(selecter){
			/*
			1. 传入 ‘’ null underfined NaN 0 false, 返回空的jQuery对象
			2. 字符串:
				代码片段:会将创建好的DOM元素存储到jQuery对象中返回
				选择器: 会将找到的所有元素存储到jQuery对象中返回
             3.数组:
             	会将数组中存储的元素依次存储到jQuery对象中立返回
             4.除上述类型以外的:
             	会将传入的数据存储到jQuery对象中返回
			*/
			// 1. 传入 ‘’ null underfined NaN 0 false, 返回空的jQuery对象
			if(!selector){
				return this;
			}
			// 2. 字符串
			else if(typeof selector === "string"){
				//2.1. 判断是否是代码片段
				if(selector.charAt(0) === "<" && selector.charAt(selector.length - 1) == ">" && selector.length >= 3){
					//1. 根据代码片段创建所有的元素
					var temp = document.createElement("div");
					temp.innerHTML = selector;
					//2. 将创建好的一级元素添加到jQuery当中
					for(var i = 0; i < temp.children.length; i++){
						this[i] = temp.children[i];
					}
					//3. 给jQuery对象添加length属性
					this.length = temp.children.length;
					//4. 返回加工好的this(jQuery)
					return this;
				}
				//2.2. 判断是否是选择器
			}
		}
	}
	njQuery.prototype.init.prototype = njQuery.prototype;
	window.njQuery = window.$ = njQuery;
})(window);

3. jQuery入口函数——工具方法抽取

// 基本结构
(function(window,undefined){
	var njQuery = function(selector){
		return new njQuery.prototype.init(selector);
	}
	njQuery.prototype = {
		constructor:njQuery,
		init:function(selecter){
			/*
			1. 传入 ‘’ null underfined NaN 0 false, 返回空的jQuery对象
			2. 字符串:
				代码片段:会将创建好的DOM元素存储到jQuery对象中返回
				选择器: 会将找到的所有元素存储到jQuery对象中返回
             3.数组:
             	会将数组中存储的元素依次存储到jQuery对象中立返回
             4.除上述类型以外的:
             	会将传入的数据存储到jQuery对象中返回
			*/
			// 0. 去除字符串两端的空格
			selector = njQuery.trim(selector);
			// 1. 传入 ‘’ null underfined NaN 0 false, 返回空的jQuery对象
			if(!selector){
				return this;
			}
			// 2. 字符串
			else if(njQuery.isString(selector)){
				//2.1. 判断是否是代码片段
				if(njQuery.isHTML(selector)){
					//1. 根据代码片段创建所有的元素
					var temp = document.createElement("div");
					temp.innerHTML = selector;
					//2. 将创建好的一级元素添加到jQuery当中
					for(var i = 0; i < temp.children.length; i++){
						this[i] = temp.children[i];
					}
					//3. 给jQuery对象添加length属性
					this.length = temp.children.length;
					//此时此刻的this是njQuery对象
					//4. 返回加工好的this(jQuery)
					return this;
				}
				//2.2. 判断是否是选择器
			}
		}
	}
	njQuery.isString = function(str){
		return typeof str === "string"
	}
	njQuery.isHTML = function(str){
		return str.charAt(0) === "<" && str.charAt(str.length - 1) == ">" && str.length >= 3
	}
	njQuery.trim = function(str){
		//判断是否支持trim方法
		if(str.trim){
			return str.trim();
		}else{
			return str.replace(/^\s+|\s+$/g,"");
		}
		
	njQuery.prototype.init.prototype = njQuery.prototype;
	window.njQuery = window.$ = njQuery;
})(window);

4. jQuery入口函数——代码片段优化

// 2. 字符串
else if(njQuery.isString(selector)){
	//2.1. 判断是否是代码片段
	if(njQuery.isHTML(selector)){
		//1. 根据代码片段创建所有的元素
		var temp = document.createElement("div");
		temp.innerHTML = selector;
		/*
		//2. 将创建好的一级元素添加到jQuery当中
		for(var i = 0; i < temp.children.length; i++){
			this[i] = temp.children[i];
		}
		//3. 给jQuery对象添加length属性
		this.length = temp.children.length;
		*/
		[].pish.apply(this,temp.children);
		//此时此刻的this是njQuery对象
		//4. 返回加工好的this(jQuery)
		return this;
	}
  • 为什么[].pish.apply(this,temp.children);能替换2,3部分
apply和call方法
  1. 通过window.test找到test方法
  2. 通过apply(obj)将找到的test方法内部的this修改为自定义的对象
function test() {
    console.log(this);
}
// window.test(); // 此时 this 为 window
// 自定义对象
var obj = {"name": "lnj2"};
// 1. 通过window.test找到test方法
// 2. 通过apply(obj)将找到的test方法内部的this修改为自定义的对象
window.test.apply(obj); //此时 this 为 obj 对象
window.test.call(obj); //此时 this 为 obj 对象
  • apply和call方法的作用:
    • 专门用于修改方法内部的this
  • 格式:
    • call(对象, 参数1, 参数2, …);
    • apply(对象, [数组]);
function sum(a, b) {
    console.log(this);
    console.log(a + b);
}
window.sum.call(obj,1,2) // 此时 this 为 obj ,a=1,b=2

// 1. 通过window.test找到test方法
// 2. 通过apply(obj)将找到的test方法内部的this修改为自定义的对象
// 3. 将传入数组中的元素依次取出, 传递给形参
window.test.apply(obj,[3,5]); //此时 this 为 obj 对象, a=3.b=5
  • 通过 push 方法连接 apply
/*
1.通过[].push找到数组中的push方法
2.通过apply(obj)将找到的push方法内部的this修改为自定义的对象
3.将传入数组中的元素依次取出, 传递给形参
*/
var arr = [1, 3, 5, 7, 9];
var obj = {};
[].push.apply(obj, arr); // arr 中的元素都转到 obj 对象中了
console.log(obj);

5. jQuery入口函数——真伪数组转

  • 真数组转伪数组
// 真数组转换伪数组的一个过程
var arr = [1, 3, 5, 7, 9];
var obj = {};
[].push.apply(obj, arr); 
console.log(obj);
  • 系统自带的伪数组转化为真数组 (IE8及其以下有bug)
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);
  • 利用 slice 方法将伪数组转化真数组(推荐)
    • 如果slice方法什么参数都没有传递, 会将数组中的元素放到一个新的数组中原样返回
window.onload = function (ev) {
    // 系统自带的伪数组
    var res = document.querySelectorAll("div");
    // 自定义的伪数组
    var obj = {0:"lnj", 1:"33", length: 2};
    // 如果想将伪数组转换为真数组那么可以使用如下方法
    var arr = [].slice.call(obj);
    console.log(arr);
}

6. jQuery入口函数——选择器处理

// 2.2判断是否是选择器
else{
    // 1.根据传入的选择器找到对应的元素
    var res = document.querySelectorAll(selector);
    // 2.将找到的元素添加到njQuery上
    [].push.apply(this, res);
    // 3.返回加工上的this
    return this;
}

7. jQuery入口函数——数组处理

else if(typeof selector === "objector" && "length" in selector && selector !== window){
	// 1.真数组
	if(({}).toString.apply(selector) === "[object Array]"){
		[].push.apply(this,selector);
		return this;
	}
	// 2.假数组
	else{
		// 将自定义的伪数组转换为真数组
		var arr = [].slice.call(selector);
		// 将真数组转换为伪数组
		[].push.apply(this,arr);
		return this;
	}
}
  • 优化
	else if(njQuery.isArray(selector){
		/*
		// 1.真数组
		if(({}).toString.apply(selector) === "[object Array]"){
			[].push.apply(this,selector);
			return this;
		}
		// 2.假数组
		else{
			// 将自定义的伪数组转换为真数组
			var arr = [].slice.call(selector);
			// 将真数组转换为伪数组
			[].push.apply(this,arr);
			return this;
		}
		*/
		// 将自定义的伪数组转换为真数组
		var arr = [].slice.call(selector);
		// 将真数组转换为伪数组
		[].push.apply(this,arr);
		return this;
	}
}
njQuery.isObject = function(sele){
	return typeof sele === "object"
}
njQuery.isWindow = function(sele){
	return sele === window;
}
njQuery.isArray = function(sele){
	if(njQuery.isObject(sele) && !njQuery.isWindow(sele) && "length" in sele){
		return true;
	}
	return false;
}

8. jQuery入口函数——其他类型处理

// 5.除上述类型以外
else{
    this[0] = selector;
    this.length = 1;
    // return this;
}
return this;

9. jQuery入口函数——extend方法

function njQuery(){
	
}
njQuery.extend = function(obj){
	// 此时此刻 this 就是 njQuery 这个类
	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({});

10. jQuery入口函数——函数处理

njQuery.extend({
	ready: function (fn) {
       // 判断DOM是否加载完毕
       if(document.readyState == "complete"){
           fn();
       }else if(document.addEventListener){
           document.addEventListener("DOMContentLoaded", function () {
               fn();
           });
       }else{
           document.attachEvent("onreadystatechange", function () {
               if(document.readyState == "complete"){
                  fn();
               }
           });
       }
   }
});
  • jQuery 监听 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");
});
/*
document.readyState属性有如下的状态
uninitialized - 还未开始载入
loading - 载入中
interactive - 已加载,文档与用户可以开始交互
complete - 载入完成

onreadystatechange事件就是专门用于监听document.readyState属性的改变的
*/
document.attachEvent("onreadystatechange", function () {
    if(document.readyState == "complete"){
        console.log("onreadystatechange");
    }
});

3. jQuery原型属性与方法

1. jQuery原型上的属性

jQuery原型上的属性:

  • jquery 获取jQ版本号
  • selector 实例默认的选择器取值
  • length 实例默认的长度
  • push 给实例添加新元素
  • sort 对实例中的元素进行排序
  • splice 按照指定下标指定数量删除元素,也可以替换删除的元素
njQuery.prototype = {
      constructor: njQuery,
      jquery:"1.1.0",
      selector:"",
      length:0,
      // [].push找到数组的push方法
      // 冒号前面的push将来由njQuery对象调用
      // 相当于[].push.apply(this);
      push:[].push,
      sort:[].sort,
      splice:[].splice
  }

2. jQuery原型上的方法

jQuery原型上的核心方法:

  • toArray 把实例转换为数组返回
  • get 获取指定下标的元素,获取的是原生DOM
  • eq 获取指定下标的元素,获取的是jQuery类型的实例对象
  • first 获取实例中的第一个元素,是jQuery类型的实例对象
  • last 获取实例中的最后一个元素,是jQuery类型的实例对象
  • each 遍历实例,把遍历到的数据传给回调使用
  • map 遍历实例,把遍历到的数据传给回调使用,然后把回调的返回值收集起来组成一个新的数组返回
1. toArray

把实例转换为数组返回

var res = $("div");
console.log(res);
var res2 = res.toArray();
console.log(res2);
njQuery.prototype = {
	toArray:function(){
	// 伪数组转真数组
	    return [].slice.call(this)
	  } 
  }

结果:
在这里插入图片描述

2. get

获取指定下标的元素,获取的是原生DOM

var res = $("div");
console.log(res); // length = 3
// get方法如果不传递参数, 相当于调用toArray()
console.log(res.get());
console.log(res.get(0));//取第0个div
console.log(res.get(1));//取第1个div
console.log(res.get(-1)); // (3 + -1) = 2 //取第2个div
console.log(res.get(-2)); // (3 + -2) = 1 //取第1个div
njQuery.prototype = {
	get:function(num){
          // 没有传递参数
          if(arguments.length === 0){
            return this.toArray();
          }
          // 传递不是负数
          else if(num >= 0){
            return this[num]
          }
          // 传递负数
          else {
            return this[this.length + num];
          }
    }
}
3. eq

获取指定下标的元素,获取的是jQuery类型的实例对象

var res = $("div");
console.log(res.eq());
console.log(res.eq(0));
console.log(res.eq(-1));
njQuery.prototype = {
	eq:function (num) {
         // 没有传递参数
         if(arguments.length === 0){
           return new jQuery()
         }else{
           return njQuery(this.get(num));
         }
     }
}
4. first 和 last
  • first 获取实例中的第一个元素,是jQuery类型的实例对象
  • last 获取实例中的最后一个元素,是jQuery类型的实例对象
var res = $("div");
console.log(res.first());
console.log(res.last());
njQuery.prototype = {
	first:function(){
      return this.eq(0);
    },
    last:function(){
      return this.eq(-1);
    }
}
5. each

遍历实例,把遍历到的数据传给回调使用

var arr = [1, 3, 5, 7, 9];
var obj1 = {0:"lnj",1:"333",2:"male",length:3};
var obj2 = {"name":"lnj","age":"33"};
njQuery.each(arr,function(key,value){
	console.log(key,value);
});
njQuery.each(arr, function (key, value) {
    if(key === 2){
    // true 为跳过2,下面继续执行
    // return true
    // false 为2下面所有都不执行
       return false;
    }
    console.log(key, value);
    console.log(this); // this 为 value -->为了方便使用
});
var arr = [1, 3, 5, 7, 9];
var obj1 = {0:"lnj",1:"333",2:"male",length:3};
var obj2 = {"name":"lnj","age":"33"};
$(arr).each(function (key, value) {
    // console.log(key, value);
    console.log(this);
});
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;
	  }
    }
  }
}
6. map

遍历实例,把遍历到的数据传给回调使用,然后把回调的返回值收集起来组成一个新的数组返回

var arr = [1, 3, 5, 7, 9];
var obj1 = {0:"lnj",1:"333",2:"male",length:3};
var obj2 = {"name":"lnj","age":"33"};
var res = njQuery.map(arr, function (value, key) {
    // console.log(value, key);
    if(key === 2){
        return value;
    }
});
console.log(res);
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 objd{
	    var temp = fn(obj[key],key);
	    if(temp){
			res.push(temp);
		}
	  })
	}
	return res;
}

4. jQueryDOM操作相关方法

1. empty 方法

清空指定元素中的所有内容

$(function () {
    var btn = document.getElementsByTagName("button")[0];
    btn.onclick = function () {
        $("div").empty();
        console.log($("div").empty());
    }
});
// DOM操作相关方法
njQuery.prototype.extend({
    empty: function () {
        // 1.遍历指定的元素
        this.each(function (key, value) {
            value.innerHTML = "";
        });
        // 2.方便链式编程
        return this;
    }
})

2. remove 方法

删除所有的元素或指定元素

$(function () {
    var btn = document.getElementsByTagName("button")[0];
    btn.onclick = function () {
        $("div").remove();
        console.log($("div").remove());
        $("div").remove(".box");
    }
});
// DOM操作相关方法
njQuery.prototype.extend({
	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;
	}
})

3. html 方法

置所有元素的内容,获取第一个元素的内容

$(function () {
	  var btn = document.getElementsByTagName("button")[0];
	  btn.onclick = function () {
	      var $div = $("div");
	      console.log($div.html());
	      $div.html("123");
	      $div.html("<div><span>我是span</span></div>");
	  }
});
// DOM操作相关方法
njQuery.prototype.extend({
   html: function (content) {
           if(arguments.length === 0){
               return this[0].innerHTML;
           }else{
               this.each(function (key, value) {
                   value.innerHTML = content;
               })
           }
   }
})

4. text 方法

设置所有元素的文本内容,获取所有元素的文本内容

$(function () {
	  var btn = document.getElementsByTagName("button")[0];
	  btn.onclick = function () {
	      var $div = $("div");
	      console.log($div.text());
          $div.text("123");
          $div.text("<div><span>我是span</span></div>");

          console.log($div.get(0).innerText);
	  }
});
// DOM操作相关方法
njQuery.prototype.extend({
   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;
                });
         }
   }
})

5. appendTo 方法

将元素添加到指定元素内部的最后

  • 特点:
    • 如果指定元素有多个,会将元素拷贝多份添加到指定元素中
    • 给appendTo方法传递字符串, 会根据字符串找到所有对应元素后再添加
    • 给appendTo方法传递jQuery对象,会将元素添加到jQuery对象保存的所有指定元素中
    • 给appendTo方法传递DOM元素, 会将元素添加到所有指定DOM元素中
// DOM操作相关方法
njQuery.prototype.extend({
   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);
    }
})

6. prependTo 方法

将元素添加到指定元素内部的最前面

// DOM操作相关方法
njQuery.prototype.extend({
   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);
    }})

7. append 方法

将元素添加到指定元素内部的最后

// DOM操作相关方法
njQuery.prototype.extend({
   append: function (sele) {
        // 判断传入的参数是否是字符串
        if(njQuery.isString(sele)){
            this[0].innerHTML += sele;
        }else{
            $(sele).appendTo(this);
        }
        return this;
   }
})

8. prepend 方法

将元素添加到指定元素内部的最前面

// DOM操作相关方法
njQuery.prototype.extend({
   prepend: function (sele) {
       // 判断传入的参数是否是字符串
       if(njQuery.isString(sele)){
           this[0].innerHTML = sele + this[0].innerHTML;
       }else{
           $(sele).prependTo(this);
       }
       return this;
   }
})

9. insertBefore,insertAfter

insertBefore—将元素添加到指定元素外部的前面
insertAfter—将元素添加到指定元素外部的后面
注意:实现insertAfter需要用到原生JavaScript的nextSibling属性

function insertBefore(source, target) {
    /*
    调用者.insertBefore(插入的元素, 参考的元素);
    insertBefore方法, 调用者是谁就会将元素插入到谁里面
    */
    // 1.拿到指定元素的父元素
    var parent = target.parentNode;
    // 2.利用指定元素的父元素来调用insertBefore方法
    parent.insertBefore(source, target);
}
var p = document.querySelector("p");
var div = document.querySelector("div");
// insertBefore(p, div);
// DOM操作相关方法
njQuery.prototype.extend({
   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);
    }
})

10. next 方法

获取紧邻的后面同辈元素的元素

// DOM操作相关方法
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);
   }
})

11. prev 方法

获取元素紧邻的前一个同辈元素

// DOM操作相关方法
njQuery.prototype.extend({
   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);
  }
})

12. replaceAll 方法

替换所有指定元素

// DOM操作相关方法
njQuery.prototype.extend({
   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);
    }
})

5. jQuery 属性操作相关方法

1. attr 方法

设置或者获取元素的属性节点值

$(function () {
    // 传递一个参数, 返回第一个元素属性节点的值
    console.log($("span").attr("class"));

    // 传递两个参数, 代表设置所有元素属性节点的值
    // 并且返回值就是方法调用者
    console.log($("span").attr("class", "abc"));

    // 传递一个对象, 代表批量设置所有元素属性节点的值
    $("span").attr({
        "class": "123",
        "name": "888"
    });
});
// 属性操作相关的方法
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;
     }
})

2. prop 方法

设置或者获取元素的属性值

$(function () {
    // 传递两个参数, 代表设置所有元素属性节点的值
    // 并且返回值就是方法调用者
    console.log($("span").prop("abc", "lnj"));

    // 传递一个参数, 返回第一个元素属性节点的值
    console.log($("span").prop("abc"));

    // 传递一个对象, 代表批量设置所有元素属性节点的值
    $("span").prop({
        "aaa": "111",
        "bbb": "222"
    });
});
// 属性操作相关的方法
njQuery.prototype.extend({
     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;
    }
})

3. css 方法

设置获取样式

$(function () {
    // 传递一个参数, 返回第一个元素指定的样式
    console.log($('div').css('height'));

    // 传递两个参数, 代表设置所有元素样式
    // 并且返回值就是方法调用者
    console.log($('div').css('height', '50px'));

    // 传递一个对象, 代表批量设置所有元素样式
    $('div').css({
        height: '50px',
        backgroundColor: 'pink'
    });

    // 获取样式
    var div = document.querySelector("div");
    console.log(window.getComputedStyle(div)["height"]);
    console.log(div.currentStyle["height"]);

    // 设置样式
    div.style["height"] = "200px";
});
// 属性操作相关的方法
njQuery.prototype.extend({
     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;
     }
})
// 工具方法
njQuery.extend({
	getStyle: function (dom, styleName) {
          if(window.getComputedStyle){
              return window.getComputedStyle(dom)[styleName];
          }else{
              return dom.currentStyle[styleName];
          }
    }
})

4. val 方法

获取设置value的值

$(function () {
    // 不传递参数, 返回第一个元素指定的样式
    console.log($('input').val());

    // 传递两个参数, 代表设置所有元素样式
    // 并且返回值就是方法调用者
    console.log($('input').val( '新设置的' ));

    var input = document.querySelector("input");
    // input.setAttribute("value", "123456");
    var btn = document.querySelector("button");
    btn.onclick = function (ev) {
    // console.log(input.getAttribute("value"));
    // console.log($('input').val());
    console.log(input.value);
    }
});
// 属性操作相关的方法
njQuery.prototype.extend({
     val: function (content) {
            if(arguments.length === 0){
                return this[0].value;
            }else{
                this.each(function (key, ele) {
                    ele.value = content;
                });
                return this;
            }
        }
})

5. hasClass 方法

判断元素中是否包含指定类

$(function () {
    // 传递参数, 只要调用者其中一个包含指定类就返回true,否则返回false
    console.log($("div").hasClass("cc"));
    console.log($("div").hasClass("abc"));

    // 没有传递参数, 返回false
    console.log($("div").hasClass());

    var div = document.querySelector("div");
    // console.log(div.getAttribute("class"));
    // console.log(div.className);
    // 1.获取元素中class保存的值
    var className = " "+div.className+" ";
    // 2.通过indexOf判断是否包含指定的字符串
    // console.log(className.indexOf("abc") != -1);
    // console.log(className.indexOf("bb"));
    // console.log(className.indexOf(" "+"bb"+" "));
    console.log(className.indexOf(" "+"dd"+" "));
});
// 属性操作相关的方法
njQuery.prototype.extend({
    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;
         }
     }
})

6. addClass 方法

给元素添加一个或多个指定的类

$(function () {
    // 传递参数, 如果元素中没有指定类就添加, 有就不添加
    // 会返回this方便链式编程
    // console.log($("div").addClass("abc"));
    // console.log($("div").addClass("abc def"));

    // 没有传递参数,不做任何操作,返回this
    console.log($("div").addClass());

    // "aabb" + " " + "abc" = "aabb abc"
});
// 属性操作相关的方法
njQuery.prototype.extend({
    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;
    }
})

7. removeClass 方法

删除元素中一个或多个指定的类

$(function () {
    // 传递参数, 如果元素中有指定类就删除
    // 会返回this方便链式编程
    console.log($("div").removeClass("aabb"));
    // console.log($("div").removeClass("aabb abc"));

    // 没有传递参数, 删除所有类
    // console.log($("div").removeClass());
});
// 属性操作相关的方法
njQuery.prototype.extend({
    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;
   	}
})

8. toggleClass 方法

没有则添加,有则删除

(function () {
    // 传递参数, 如果元素中没有指定类就添加, 有就不添加
    // 会返回this方便链式编程
    console.log($("div").toggleClass("abc"));
    console.log($("div").toggleClass("aabb abc"));

    // 没有传递参数, 删除所有类
    console.log($("div").toggleClass());
});
// 属性操作相关的方法
njQuery.prototype.extend({
    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;
    }
})

9. clone 方法

复制一个元素

$(function () {
    $("button").eq(0).on("click",function () {
        // 1.浅复制一个元素
        var $li = $("li").clone(false);
        console.log($li);
        // 2.将复制的元素添加到ul中
        $("ul").append($li);
    });

    $("button").eq(1).on("click", function () {
        // 1.深复制一个元素
        var $li = $("li").clone(true);
        // 2.将复制的元素添加到ul中
        $("ul").append($li);
    });

    /*
    li.eventsCache = {
        click: [];
    };
    */
    $("li").on("click", function () {
        alert($(this).html());
    });

    var li = document.querySelector("li");
    li.onclick = function (ev) {
        alert(123);
    }
    var temp = JSON.parse(JSON.stringify(li));
    var ul = document.querySelector("ul");
    ul.appendChild(temp);
});
// 属性操作相关的方法
njQuery.prototype.extend({
    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);
        }
    }
})

6. jQuery 事件操作相关方法

1. on(type, callback)

注册事件

  • 注册多个相同类型事件, 后注册的不会覆盖先注册的
  • 注册多个不同类型事件, 后注册的不会覆盖先注册的
// 事件操作相关的方法
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;
    }
});

2. off(type, callback)

移出事件

$(function () {
    // 1.不传参, 会移除所有事件
    $("button").off();
    // 2.传递一个参数, 会移除对应类型所有事件
    $("button").off("click");
    // 3.传递两个参数, 会移除对应类型对应事件
    $("button").off("click", test1);
});
// 事件操作相关的方法
njQuery.prototype.extend({
    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;
	  }
});
  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值