一、初识jquery
1.1、初识jQuery
1.jQuery是什么?
//1.利用原生js查找dom元素
var div1 = document.getElementsByTagName("div")[0];
var div2 = document.getElementsByClassName("box1")[0];
var div3 = document.getElementById("box2");
console.log(div1, div2, div3);
//2.利用原生js修改背景颜色
div1.style.backgroundColor = "red";
div2.style.backgroundColor = "yellow";
div3.style.backgroundColor = "blue";
//1.利用jquery查找dom元素
var $div1 = $("div");
var $div2 = $(".box1");
var $div3 = $("#box2");
//1.利用jquery查找设置背景
$div1.css({
backgroundColor:"red",
width:"200px",
height:"200px"
});
$div2.css({
backgroundColor:"red"
});
$div3.css({
backgroundColor:"red"
});
2.为何使用jquery
3.如何选择jquery
进入jquery官网——downloader——下拉到最下面——点击jquery cdn——选择jquery版本
1.x:兼容ie678,但相对其它版本文件较大,官方只做BUG维护,功能不再新增,最终版本:1.12.4 (2016年5月20日).
2.x:不兼容ie678,相对1.x文件较小,官方只做BUG维护,功能不再新增,最终版本:2.2.4 (2016年5月20日)
3.x:不兼容ie678,只支持最新的浏览器,很多老的jQuery插件不支持这个版本,相对1.x文件较小,提供不包含Ajax/动画API版本。
应该选择几点几版本jQuery?
1.2、jQuery使用
1.下载jquery库:下载地址: http://code.jquery.com/
2.引入下载的jQuery库
除了1.x,2.x,3.x外,每个版本还提供两种类型:uncompressed和conmpressed类型。
uncompressed:未压缩的版本,有换行,格式好看,单词完整。开发过程中使用。
conmpressed:压缩的版本,min。版本中无空格换行。项目上线后使用。
jquery官网虽然为了页面的简洁性并未在Download页面提供全部的下载链接,但各个版本都以一个简单的规律存在它的网站中;
如果我们要下载1.8.3版本的jquery,你只需访问该地址http://code.jquery.com/jquery-1.8.3.js (未压缩版) 或者http://code.jquery.com/jquery-1.8.3.min.js (压缩版)
如果我们要下载1.12.4版本的jquery,访问的地址是http://code.jquery.com/jquery-1.12.4.js (未压缩版) 或者http://code.jquery.com/jquery-1.12.4.min.js (压缩版)
3.编写jQuery代码
//原生js固定写法。能拿到body中所有元素的格式
window.onload = function (ev) {}
//jQuery的固定写法。能拿到body所有元素的格式
$(document).ready(function () {
alert("hello inj");
});
1.3、jQuery和js加载模式
1.原生JS和jQuery入口函数的加载模式不同
原生JS会等到DOM元素加载完毕,并且图片也加载完毕才会执行。
jQuery会等到DOM元素加载完毕但不会等到图片也加载完毕才会执行
2.原生的JS如果编写了多个入口函数,后面编写的会覆盖前面编写的。
window.onload = function (ev) {
alert("hello JS1");//不显示
}
window.onload = function (ev) {
alert("hello JS2");//显示
}
jQuery中编写多个入口函数,后面的不会覆盖前面的。
$(document).ready(function () {
alert("hello jQuery1")//先显示
});
$(document).ready(function () {
alert("hello jQuery2")//后显示
});
不会覆盖的本质(了解,后面jQuery原理会详细讲解)
为什么我们能访问$符号?
JavaScript中如何定义一个全局变量?
function test () {
var customValue = 998;
alert(customValue);
// 1.没有如下代码customValue就不是一个全局变量,函数执行完毕之后
// customValue会被自动释放,test函数以外的地方访问不到customValue
// 2.加上如下代码之后customValue就会变成一个全局变量,函数执行完毕也不
// 会被释放,test函数以外的地方可以访问customValue
// window.customValue = customValue;
}
test();
alert(customValue);
所以jQuery框架源码实现
window.jQuery = window.$ = jQuery;
1.4、jQuery入口函数其它写法
//1.第一种写法
$(document).ready(function () {
alert("hello jQuery1");
});
//2.第二种写法(比第一种写的多,编码效率低一些)
jQuery(document).ready(function () {
alert("hello jQuery2");
});
//3.第三种写法(推荐)
$(function () {
alert("hello jQuery3");
});
//4.第四种写法
jQuery(function () {
alert("hello jQuery4");
});
/*企业开发中推荐使用第三种写法。原因:写的更少,做的更多*/
1.5、jQuery冲突问题
使用jquery和其他框架,都遇到$来写的更少,做的更多时,会出现冲突
解决方案:
1.释放$的使用权
jQuery.noConflict();
注意点:释放操作必须在编写其它jQuery代码之前写
释放之后就不能使用$,只能使用jQuery
2.自定义一个访问符号
var nj = jQuery.noConflict();释放$符号,改为使用nj
//jQuery.noConflict();释放“$”符号的使用权,jQuery不使用$符号了
var nj = jQuery.noConflict();
nj(function () {
alert("hello jq1")
})
二、jQuery核心函数和工具方法
2.1、jQuery核心函数
$();就代表调用jQuery的核心函数
核心函数可以接受的参数
1.接受一个函数(入口函数)
jQuery(callback)
当DOM加载完成后执行传入的回调函数
2.接受一个字符串
2.1、接受一个字符串选择器
2.2、接受一个字符串代码片段
jQuery(html,[ownerDoc])
根据 HTML 标记字符串,动态创建DOM 元素
3.接受一个DOM元素
//接受一个函数
$(function(){
alert("hello jq");
//接受一个字符串选择器
//传递的是一个jQuery的字符串选择器,返回一个jQuery对象,对象中保存了找到的DOM元素
var $box1 = $(".box1");
var $box2 = $("#box2");
console.log($box1);
console.log($box2);
//接受一个字符串代码片段
//传递的是一个jQuery的字符串代码片段,返回一个jQuery对象,对象中保存了创建的DOM元素
var $p = $("
我是段落
");console.log($p);
$box1.append($p);
//接受一个DOM元素
//如果将原生的DOM元素传给jQuery的核心函数,原生的DOM元素会被包装成一个jQuery对象返回给我们。
// 利用js原生语法获取所有div,得到的是一个js对象
var span = document.getElementsByTagName("span")[0];
console.log(span);
var $span = $(span);
console.log($span);
});
注意:为了方便开发者之间沟通和阅读,一般情况下所有jQuery操作相关的变量前面加上$
2.2、jQuery对象
1.什么是jQuery对象
jQuery是个伪数组
2.什么是伪数组?
有0到length-1的属性,并写有length属性。
$(function () {
var $div = $("div");//找到所有div,将div包装到jQuery对象中。
console.log($div);
var arr = [1,3,5];//对比jQuery和数组
console.log(arr);
});
2.3、静态方法和实例方法(js中的)
//1.定义一个类
function AClass(){
}
//2.给这个类添加一个静态方法
//直接添加给类的就是静态方法
AClass.staticMethod = function () {
alert("staticMethod");
}
//静态方法通过类名调用
AClass.staticMethod();
//3.给这个类添加一个实例方法(实例方法是添加给类的原型的)
AClass.prototype.instanceMethod = function () {
alert("instanceMethod");
}
//实例方法通过类的实例调用
//创建一个实例(创建一个对象)
var a = new AClass();
//通过实例调用实例方法
a.instanceMethod();
静态方法:直接添加到类上。通过类名调用
实例方法:添加到类的原型上面的。通过实例调用
2.4、jQuery-each方法
1.原生js的遍历
第一个参数:遍历到的元素
第二个参数:当前遍历到的索引
注意点:
原生的forEach方法只能遍历数组,不能遍历伪数组
//定义一个数组
var arr = [1, 3, 5, 7, 9];
var obj = {0:1, 1:3, 2:5, 3:7, 4:9, length:5};//创建一个对象,伪数组就是对象
//原生js的遍历
/*
第一个参数:遍历到的元素
第二个参数:当前遍历到的索引
注意点:
原生的forEach方法只能遍历数组,不能遍历伪数组
* */
arr.forEach(function (value,index) {
console.log(index,value);
});
obj.forEach(function (value,index) {
console.log(index,value);//报错obj.forEach is not a function
});
2.利用jquery的each静态方法遍历数组
第一个参数:遍历哪个数组(arr)
第二个参数:遍历之后执行哪个回调(function)
回调函数中第一个参数:当前遍历到的索引,
回调函数中第二个参数:遍历到的元素
注意点:jquery的each方法是可以遍历伪数组的。
$.each(arr, function (index, value) {
console.log(index,value);//可以遍历原生数组,原生回调函数先传value,jquery回调函数先传索引
});
$.each(obj, function (index, value) {
console.log(index,value);//可以遍历伪数组
})
2.5、jQuery-map方法
1.利用原生JS的map方法遍历
第一个参数:当前遍历到的元素
第二个参数:当前遍历到的索引
第三个参数:当前被遍历的数组
注意点:和原生的forEach一样,不能遍历伪数组
//定义一个数组
var arr = [1, 3, 5, 7, 9];
var obj = {0:1, 1:3, 2:5, 3:7, 4:9, length:5};//创建一个对象,伪数组就是对象
arr.map(function (value, index, array) {
//array:当前是哪个数组就把哪个数组传出
console.log(index, value, array);
});
obj.map(function (value, index, array) {
//array:当前是哪个数组就把哪个数组传出
console.log(index, value, array);//obj.map is not a functi
2.利用jQuery的map方法遍历
第一个参数:要遍历的数组
第二个参数:每遍历一个元素之后执行的回调函数
回调函数的参数:
第一个参数:遍历到的元素
第二个参数:遍历到的索引
注意点:和jquery中的each静态方法一样,map静态方法也可以遍历伪数组
$.map(arr, function (value, index) {
console.log(index, value);
});
$.map(obj, function (value, index) {
console.log(index, value);
});
3.each和map对比
jquery中的each静态方法和map静态方法的区别。
3.1.each静态方法默认的返回值是:遍历谁就返回谁
map静态方法默认的返回值是一个空数组
var res = $.map(obj, function (value, index) {
console.log(index, value);
return value + index;
});
var res2 = $.each(obj, function (index, value) {
console.log(index,value);//可以遍历伪数组
})
console.log(res);//返回空值
console.log(res2);//返回被遍历的数组或对象
3.2、each静态方法不支持在回调函数中对遍历的数组进行处理。
map静态方法可以在回调函数中通过return对遍历的数组进行处理,然后生成一个新的数组返回
var res = $.map(obj, function (value, index) {
return value + index;//返回新数组
});
var res2 = $.each(obj, function (index, value) {
return value + index;//无变化
})
2.6、jQuery其它静态方法
1、$.trim();
作用:去除字符串两端的空格
参数:需要去除空格的字符串
返回值:去除空格之后的字符串
var str = " jq1 ";
var res = $.trim(str);
console.log("---"+str+"---");
console.log("---"+res+"---");
2、$.isWindow();
作用:判断传入的对象是否是window对象
返回值:true/false
var arr = [1, 3, 5, 7, 9];//真数组 false
var arrlike = {0:1, 1:3, 2:5, 3:7, 4:9, length:5};//伪数组 false
var obj = {"name":"inj","age":"333"};//对象 false
var fn = function(){};//函数(方法) false
var w = window;//window对象 true
var res = $.isWindow(arr);
console.log(res);
3、$.isArray();
作用:判断传入的对象是否是真数组
返回值:true/false
var res = $.isArray(arrlike);
console.log(res);//伪数组faler
4、$.isFunction();
作用:判断传入的对象是否是函数(方法)
返回值:true/false
注意点:jQuery框架本质是一个函数,还是一个匿名函数
jQuery头尾:
(function( global, factory ) {//本质上是个函数
})(window);
函数到jQuery格式的演变过程:
1.
function test(){
}
test();
2.相当于将test写为小括号后放入function。变为立即执行的匿名函数
(function() {
})();
var res = $.isFunction(jQuery);
console.log(res);//返回为true
2.7、jQuery-holdReady方法
暂停、恢复ready事件
$.holdReady(true);//告诉jQuery暂停ready方法的执行
/*入口函数,页面上所有DOM元素加载完就会执行*/
$(document).ready(function () {
alert("ready")
});
/*有时企业开发中,要等别的事情做完才执行入口函数,例如:等图片加载完,或其他框架加载完*/
var btn = document.getElementsByTagName("button")[0];
btn.onclick = function () {
//alert("btn")
$.holdReady(false);//恢复ready
}
2.8、通过webstorm简化操作
jQuery官方文档查询:
jQuery中文文档:
http://hemin.cn/jq/
https://www.jquery123.com/
设置jQuery快捷方式:
file——settings——Live Templates——点开HTML/XML——点击“+”,选择Live Templates添加模板,——abbreviation(快捷键),define(定义:全选)
使用方法:jq+tab
设置快速在浏览器中显示页面
file——settings——keymap——搜索default——open in default browser(右键)——选择add keyboard shortcut——输入希望的值(我输入的Ctrl+shift+o)
三、jQuery属性操作
3.1、jQuery内容选择器
页面样式:
:empty:找到既没有文本内容也没有子元素的指定元素。
$(document).ready(function () {
var $div = $("div:empty")//找到所有的div,并且从中找到内容为空的。(空:没有文本也没有子元素,第一个div)
console.log($div);//返回第一个div
});
:parent 作用:找到有文本内容或有子元素的指定元素。
$(document).ready(function () {
var $div2 = $("div:parent");//找到所有的div,并且从中找到有文本内容或者有子元素的。
console.log($div2);//结果为第2,3,4个div
});
:contains(text) 作用:找到包含指定文本内容的指定元素。
$(document).ready(function () {
var $div3 = $("div:contains('我是div')");//找到所有的div,并且从中找到包含文本内容"我是div"的。
console.log($div3);//结果为第2,3个div
});
:has(selector) 作用:找到包含指定子元素的指定元素
$(document).ready(function () {
var $div4 = $("div:has('span')");//找到所有的div,并且从中找到包含子元素span的div。
console.log($div4);//结果为第4个div
});
3.2、属性和属性节点
1.什么是属性?
属性就是对象身上保存的变量
只要对象身上都可以添加属性(无论是自定义对象,还是DOM对象)
// 1.自定义一个对象
var obj = {};
console.log(obj);
// 2.动态给自定义对象添加属性
obj.name = "lnj"; // name就是对象obj的一个属性
obj.age = 33; // age就是对象obj的一个属性
console.log(obj);
2.如何操作属性?
赋值:对象.属性名称 = 值;
对象["属性名称"] = 值;
获取:对象.属性名称;
对象["属性名称"];
3.什么是属性节点
在编写HTML代码时,在HTML标签(span)中添加的属性(name)就是属性节点
在浏览器中找到span这个DOM元素(对象)之后,展开看到的都是属性,在attributes属性中保存的所有内容都是属性节点。
任何对象都有属性,只有DOM元素有属性节点。所有的属性节点都保存在DOM元素的attributes属性中。
4.如何操作属性节点
设置属性节点值:DOM元素.setAttribute("属性名称","属性值");
获取属性节点值:DOM元素.getAttribute("属性名称")
5.属性和属性节点有什么区别?
任何对象都有属性,只有DOM对象才有属性节点。
上图中:点击“0:span”展开后的都是属性,应为span是DOM元素(对象),对象中的都是属性。
上图中点击“0:span”,展开其中的“attributes”属性。里面的内容都是属性节点。
3.3、jQuery-attr方法
1.attr(name|pro|key,val|fn)
作用:获取或者设置属性节点的值,可以传递一个参数,也可以传递两个参数。
如果传递一个参数,代表获取属性节点的值。
如果传递两个参数,代表设置属性节点的值。
注意点:
如果是获取:无论找到多少个元素,都只会返回第一个元素指定的属性节点的值。
如果是设置:找到多少个元素就会设置多少个元素
如果是设置:如果设置的属性几点不存在,那么系统会自动新增。
$(document).ready(function () {
console.log($("span").attr("class"));//打印span1
$("span").attr("class","box");//两个span的class都会修改为box
$("span").attr("abc","123");
});
2.removeAttr(name)
作用:删除属性节点
注意点:会删除所有找到元素指定的属性节点。
同时删除多个属性节点,在属性节点之间加入“空格”即可
$("span").removeAttr("class name");
$("span").removeAttr("class");
$("span").removeAttr("class name");
3.4、jQuery-prop方法
1.prop(n|p|k,v|f)方法
特点和attr方法一致
2.removeProp(name) 方法
特点和removeAttr方法一致
$("span").eq(0).prop("demo","it666");//找到所有span。找到第1个span,新增demo属性,并赋值为it666
$("span").eq(1).prop("demo","lnj");//找到所有span。找到第2个span,新增demo属性,并赋值为lnj
console.log($("span").prop("demo"));;//找到所有span。找到第1个span,
});
$("span").removeProp("demo");//删除所有demo
3.注意点:
prop方法不仅能够操作属性,他还能操作属性节点。
console.log($("span").prop("class"));//获取span的class属性节点的值,打印span1
$("span").prop("class","box");//将所有span的class属性节点改为box
4.在企业开发中官方推荐在操作属性节点时,具有true和false两个属性的属性节点,如cheched,selected,或disabled使用prop(),其他的使用attr().
/* */
console.log($("input").prop("checked"));//打印true
console.log($("input").attr("checked"));//打印checked
});
/* */
console.log($("input").prop("checked"));//打印false
console.log($("input").attr("checked"));//打印undefined
3.5、attr和prop练习
$(document).ready(function () {
/*点击button获取input中的内容,并将内容给img的src属性*/
//1.给按钮添加点击事件
var btn = document.getElementsByTagName("button")[0];
btn.οnclick=function(){
//2.获取输入框输入的内容
var input=document.getElementsByTagName("input")[0];
var text = input.value;
//3.修改img的src属性节点的值
//attr和prop均可以使用,但因为src的返回值不是true或false,因此推荐使用attr。
$("img").attr("src",text);
//$("img").prop("src",text);
}
});
3.6、jQuery类操作相关方法
1.addClass(class|fn)
$("div").addClass("class1 class2");
作用:添加一个类
使用于不想将样式写死,想用js动态添加样式
添加多个类时用“空格”隔开多个类名
2.removeClass([class|fn])
$("div").removeClass("class1 class2")
作用:删除一个类
如果想删除多个,多个类名之间用“空格”隔开
3.toggleClass(class|fn[,sw])
$("div").toggleClass("class1 class2")
作用:切换类
有就删除,没有就添加。
3.7、jQuery文本值相关操作
1.html([val|fn])
//和原生js中的innerHTML一模一样。设置的是DOM,括号中的标签会变为子元素
2.text([val|fn])
//和原生js中的innerTEXT一模一样。设置的是括号中的文本。括号中的标签也作为文字传递
3.val([val|fn|arr])
3.8、jQuery操作样式方法
1.逐个设置
$("div").css("width","100px");
$("div").css("height","100px");
$("div").css("background-color","red");
2.链式设置
注意点:链式操作如果大于3步,建议分开。
$("div").css("width","100px").css("height","100px").css("background-color","blue")
3.批量设置(企业开发中推荐使用,原因:简单、直观,类似css代码)
$("div").css({
width:"100px",
height:"100px",
background:"yellow",
});
4.获取CSS样式值
console.log($("div").css("width"));//100px
console.log($("div").css("background"));//rgb(255, 255, 0) none repeat scroll 0% 0% / auto padding-box border-box
3.9、jQuery尺寸和位置操作
*{
padding: 0;
margin: 0;
}
.father{
width: 200px;
height: 200px;
background: rosybrown;
border: 50px solid #000;
margin-left: 50px;
position: relative;
}
.son{
width: 100px;
height: 100px;
background: blueviolet;
position: absolute;
left: 50px;
top: 50px;
}
$(document).ready(function () {
//编写jQuery相关代码
var btns = document.getElementsByTagName("button");
//监听获取
btns[0].onclick = function () {
//获取元素的宽度,不包括边框等内容
console.log($(".father").width());//200
//offset([coordinates])
//作用:获取元素距离窗口的偏移位
console.log($(".son").offset().left);//150
//position()
//作用:获取元素距离定位元素的偏移位
console.log($(".son").position().left);//50
}
//监听设置
btns[1].onclick = function () {
//设置元素的宽度
$(".father").width("500");
$(".son").offset({
left:10
});
/*注意点:position方法只能获取,不能设置*/
$(".son").position({
left:10
});
}
});
3.10、jQuery的scrollTop方法
获取元素滚动距离(偏移位)。
$(document).ready(function () {
//编写jQuery相关代码
var btns = document.getElementsByTagName("button");
//监听获取
btns[0].onclick = function () {
//获取div内部的滚动距离
console.log($(".scroll").scrollTop());//获取元素滚动的偏移位,第一次没滚动为0,滚动一点,点击获取就有了数值。
//注意点:为了保证浏览器的兼容,获取网页滚动的偏移位需要按照如下写法:
console.log($("body").scrollTop()+$("html").scrollTop());//获取网页滚动的偏移位,html或者body可以代表网页,IE中需要使用body,google中使用html。
}
//监听设置
btns[1].onclick = function () {
//设置滚动的偏移位
$(".scroll").scrollTop("300");
//设置网页滚动偏移位
//注意点:为了保证浏览器的兼容,获取网页滚动的偏移位需要按照如下写法:
$("html,body").scrollTop(300);
}
});
四、jQuery事件相关
4.1、jQuery事件绑定
jQuery中有两种绑定事件方式
1.evenName(fn);
编码效率略高,推荐使用。部分js事件jQuery没有实现,所以不能添加
$("button").click(function () {
alert("1")
});
2.on(evenName,fn)
编码效率略低,所有js事件都可以添加
$("button").on("click",function () {
alert("2")
});
3.注意点:
两种方法都可以添加多个相同或者不同类型的事件,不会覆盖。
4.2、jQuery事件解绑
off方法:移除事件
不传参数:移除所有事件
传递参数:移除参数事件
如果传递一个参数,会移除所有指定类型的事件。
如果传递两个参数,会移除指定类型的指定事件。
function test1() {
alert("1")
}
$("button").click(test);
$("button").off();//移除button的所有事件
$("button").off("click");//移除button的click事件
$("button").off("click",test1);//移除click类型的test1事件
4.3、jQuery事件冒泡和默认行为
1.什么是事件冒泡
事件冒泡是从目标元素逐级向上传播到根节点的过程
小明告诉爸爸他有一个女票,爸爸告诉爷爷孙子有一个女票,一级级向上传递就是事件冒泡
2.如何阻止事件冒泡(在儿子身上阻止)
方法1:return false;
方法2:event.stopPropagation();
此案例点击son的时候,father的事件也会被触发,产生冒泡。
//阻止事件冒泡方法1:return
$(".son").click(function () {
alert("son");
return false;//告诉系统不需要事件冒泡
});
//阻止事件冒泡方法2:event.stopPropagation();
$(".son").click(function (event) {
alert("son");
event.stopPropagation();
});
$(".father").click(function () {
alert("father");
});
3.什么是默认行为
网页中的元素有自己的默认行为,例如单击超链接(a标签)后会跳转,点击提交表单按钮(submit)会提交(并没有对a标签,submit进行事件监听,绑定,就触发了跳转,提交行为)
4.如何阻止默认行为
方法1:return false;
方法2:event.preventDefault();方法阻止事件默认行为
此方法点击a标签弹出altert后会跳转到百度页面,产生默认行为,为了不让塔跳转,加了return,或者event.preventDefault();方法
//阻止默认行为方法1:return false;
$("a").click(function () {
//点击a标签后alert后不要跳转。
alert("弹出注册框")
return false;
});
//阻止默认行为方法2:return false;
$("a").click(function (event) {
//点击a标签后alert后不要跳转。
alert("弹出注册框")
event.preventDefault();
});
4.4、jQuery事件自动触发
1.自动触发事件:
方法1:trigger方法
方法2:triggerHandler方法
$(".son").click(function (event) {
alert("son");
});
$(".father").click(function () {
alert("father");
});
$(".father").trigger("click");//自动触发father的click方法
$(".father").triggerHandler("click");//自动触发father的click方法
2.trigger和triggerHandler方法的区别:
trigger:如果利用trigger自动触发事件,会触发事件冒泡。
triggerHandler:如果利用triggerHandler自动触发事件,不会触发事件冒泡。
$(".son").trigger("click");//产生事件冒泡
$(".son").triggerHandler("click");//不会触发事件冒泡
trigger:如果利用trigger自动触发事件,会触发默认行为。
triggerHandler:如果利用triggerHandler,自动触发事件,不会触发默认行为。
$("input[type='submit']").click(function () {
alert("submit");
});
$("input[type='submit']").trigger("click");//触发click事件后,还会触发默认行为,跳转到http://www.taobao.com
$("input[type='submit']").triggerHandler("click");//触发click事件后,不会触发默认行为。
3.涉及自动触发的简单面试题:
$("a").click(function () {
alert("a")
});
$("a").triggerHandler("click");//alert后,不跳转到http://www.baidu.com
$("a").trigger("click");//alert后,不跳转到http://www.baidu.com。
问题:想要通过trigger自动触发a的点击事件和默认行为。失败。
解决办法:
HTML改为注册
js不触发a的click事件,触发span的click事件。
$("span").click(function () {
alert("a")
});
$("span").trigger("click");
});
4.5、jQuery自定义事件
1.什么是自定义事件
自定义事件:搞一个系统没有的事件,并且能够自动响应.自定义事件就是自己虾XX起一个不存在的事件名称来注册事件, 然后通过这个名称还能触发对应的方法执行, 这就是传说中的自定义事件
2.自定义事件的前提条件
2.1.事件必须是通过on绑定的(因为eventName是jQuery实现好的,on是所有事件都可以响应)
2.2.事件必须通过trigger来触发(因为trigger方法可以自动触发对应名称的事件,所以只要事件的名称和传递给trigger的名称一致就能执行对应的事件方法)
$(".son").on("myClick",function () {
alert("son")
});
$(".son").trigger("myClick")
4.6、jQuery事件命名空间
1.事件命名空间的由来
众所周知一个元素可以绑定多个相同类型的事件.企业多人协同开发中,如果多人同时给某一个元素绑定了相同类型的事件,但是事件处理的方式不同,就可能引发事件混乱(不知道a和b谁写了相同的哪个事件)。为了解决这个问题jQuery提出了事件命名空间的概念。
2.事件命名空间作用
事件命名空间主要用于区分相同类型的事件,区分不同前提条件下到底应该触发哪个人编写的事件。
3.事件命名空间的格式
格式: "eventName.命名空间"
4.添加事件命名空间的前提条件
4.1.事件是通过on来绑定的
4.2.通过trigger触发事件(保证只执行某个人添加的click事件。)
$(".son").on("click.zhangsan",function () {
alert("son1")
});
$(".son").on("click.lisi",function () {
alert("son2")
});
$(".son").trigger("click.lisi");
4.7、jQuery事件命名空间面试题
不带命名空间事件被trigger调用,会触发带命名空间事件
带命名空间事件被trigger调用,只会触发带命名空间事件
$(".father").on("click.lisi",function () {
alert("father click1")
});
$(".father").on("click",function () {
alert("father click2")
});
$(".son").on("click.lisi",function () {
alert("son click1")
});
利用trigger触发子元素带命名空间的事件,那么父元素带相同命名空间的事件也会被触发。而父元素没有命名空间的事件不会被触发。
$(".son").trigger("click.lisi");//产生冒泡,触发 alert("son click1")后,又触发了 alert("father click1")。
利用trigger触发子元素不带命名空间的事件,那么子元素所有相同类型的事件和父元素所有相同类型的事件都会被触发。
$(".son").trigger("click");//产生冒泡,触发 alert("son click1")后,又触发了 alert("father click1")。最后触发alert("father click2")
4.8、jQuery事件委托
1.什么是事件委托?
例如: 张三在寝室不想去食堂吃饭,那么张三可以"委托"李四帮忙带一份饭
例如: 张三先找房,但是对要找房的地点又不熟悉,那么张三可以"委托"中介帮忙找房
所以得出结论:
事件委托就是请别人帮忙做事情,然后将做完的结果反馈给我们。(找一个在入口函数执行之前就有的元素,来监听动态添加元素的某些事件。)
2.js中事件委托的好处
2.1、减少监听数量
2.2、新增元素自动有事件响应处理
3.jQuery中如何添加事件委托
添加委托前
$("button").click(function () {
$("ul").append("
});
/*
在jQuery中,如果通过核心函数找到的元素不止一个,那么再添加事件的时候,jQuery会遍历所有找到的元素,给所有找到的元素添加事件。
*/
$("ul>li").click(function () {
/*
给ul中的3个li添加click事件,点击button加li后,还是只有这3个li有click事件。
原因:click事件再jQuery的入口函数里添加的,界面上所有的DOM加载完毕后才执行入口函数,DOM加载完后只有三个li,只有他们有click事件。因此新增的li没有click响应事件。如果想新增的li也有click事件,就要用到事件委托。
*/
console.log($(this).html());//谁触发事件,this就是谁
});
添加委托后
格式:$(parentSelector).delegate(childrenSelector, eventName, callback)
$("ul").delegate隐式迭代所有ul添加事件(相比开始迭代li,必然ul的个数会少很多)
当事件被触发时,系统会自动动态查找当前是哪个li触发了事件,所以新增的li也能响应到事件
$("button").click(function () {
$("ul").append("
});
$("ul").delegate("li","click",function () {
//把li的click事件委托给ul去监听,ul在入口函数执行的时候就有了,因此可以监听到新增的li,并把click事件给新增的li,
console.log($(this).html());//拿到的是ul,为什么this是li呢?点li,li没有click事件,事件冒泡向上传递,传给ul,ul有click事件。this是从点的li冒泡传上来的。
})
4.9、jQuery事件委托练习
4.10、jQuery移入移出事件
*{
margin: 0;
padding: 0;
}
.father{
width: 200px;
height: 200px;
background: red;
}
.son{
width: 100px;
height: 100px;
background: royalblue;
}
mousemove/mouseout:当子元素被移入移出的时候也会触发父元素的事件。
$(document).ready(function () {
$(".father").mousemove(function () {
console.log("father被移入了");
});
$(".father").mouseout(function () {
console.log("father被移出了");
});
});
mouseenter/mouseleave:当子元素被移入移出的时候不会触发父元素的事件。(企业开发中推荐用这两个方法)
$(".father").mouseenter(function () {
console.log("father被移入了");
});
$(".father").mouseleave(function () {
console.log("father被移出了");
});
hover:内部是用 mouseenter/mouseleave实现的。
$(".father").hover(function () {
console.log("father被移入了");
},function () {
console.log("father被移出了");
});
$(".father").hover(function () {
console.log("father被移入移出了");
});
4.11、电影排行榜上
4.12、电影排行榜下
4.13、Tab选项卡上
4.14、Tab选项卡下
4.15、Tab选项卡终极
五、jQuery动效
5.1、jQuery显示隐藏动画
*{
margin: 0;
padding: 0;
}
div{
width: 200px;
height: 200px;
background: red;
display: none;
}
1.show([s,[e],[fn]])显示动画
内部实现原理根据当前操作的元素是块级还是行内决定, 块级内部调用display:block;,行内内部调用display:inline;
$("button").eq(0).click(function () {
//$("div").css("display","block");
$("div").show(1000,function () {
//回调函数function作用:动画执行完毕后调用
alert("显示动画执行完毕")
});
});
2.hide([s,[e],[fn]])隐藏动画
$("button").eq(1).click(function () {
//$("div").css("display","none");
$("div").hide(1000,function () {
alert("隐藏动画执行完毕")
});
});
3.toggle([spe],[eas],[fn])切换动画(显示变隐藏,隐藏变显示)
$("button").eq(2).click(function () {
$("div").toggle(1000,function () {
alert("切换动画执行完毕")
});//有就隐藏,没有就显示。1000ms=1s
});
4.注意事项:
5.2、对联广告
$(document).ready(function () {
//网页滚动到一定位置,对联广告才显示。因此要使用scroll监听网页滚动
//1.监听网页滚动
$(window).scroll(function () {
console.log("网页滚动了");
console.log($("html,body").scrollTop());//看网页滚动了多少
//1.1获取网页滚动的偏移位
var offset = $("html,body").scrollTop();
//1.2判断网页是否滚动到了指定的位置
if (offset>=500){
//1.3显示广告
$("img").show(1000);
}else{
$("img").hide(1000);
}
});
});
5.3、jQuery展开和收起动画
参数、注意事项和显示隐藏动画一模一样, 只不过动画效果不一样而已
1.slideDown([s],[e],[fn])展开动画
$("button").eq(0).click(function () {
$("div").slideDown(1000,function () {
alert("展开完毕")
});
});
2.slideUp([s,[e],[fn]])收起动画
$("button").eq(1).click(function () {
$("div").slideUp(1000,function () {
alert("收起完毕")
});
});
3.slideToggle([s],[e],[fn])切换动画(展开变收起,收起变展开)
$("button").eq(2).click(function () {
$("div").slideToggle(1000,function () {
alert("执行完毕")
});
});
5.4、折叠菜单上
5.5、折叠菜单下
*{
margin: 0;
padding: 0;
}
.nav{
list-style: none;
width: 300px;
margin: 100px auto;
}
.nav>li{
border: 1px solid #000;
line-height: 30px;
border-bottom: none;
text-indent: 2em;
position: relative;
}
.nav>li:last-child{
border-bottom: 1px solid #000;
border-bottom-right-radius: 10px;
border-bottom-left-radius: 10px;
}
.nav>li:first-child{
border-top-right-radius: 10px;
border-top-left-radius: 10px;
}
.nav>li>span{
background: url("images/arrow_right.png") no-repeat center center;
display: inline-block;
width: 32px;
height: 32px;
position: absolute;
right: 10px;
top: 3px;
}
.sub{
display: none;
}
.sub>li{
list-style: none;
background: mediumslateblue;
border: 1px solid #FFFFFF;
}
.sub>li:hover{
background: rosybrown;
}
.nav>.current>span{
transform: rotate(90deg);
}
$(document).ready(function () {
//编写jQuery相关代码
//1.监听一级菜单的点击事件
$(".nav>li").click(function () {
//1.1拿到二级菜单
var $sub = $(this).children(".sub");//找到一级菜单叫sub的儿子
console.log($(this).children(".sub"));
//1.2让二级菜单展开
$sub.slideDown(1000);
//1.3拿到所有非当前的二级菜单
var otherSub = $(this).siblings().children(".sub");//拿非当前的一级菜单,之后那一级菜单的sub儿子菜单
console.log($(this).siblings().children(".sub"));//验证一下
//1.4让所有非当前的二级菜单收起
otherSub.slideUp(1000);
//1.5让被点击的一级菜单箭头旋转
$(this).addClass("current");
//1.6让所有非被点击的一级菜单箭头还原
$(this).siblings().removeClass("current");
});
});
5.6、下拉菜单
问题:鼠标快速的移入移出时,展现了一种自嗨风格,可以试试。
事情搞这么大的原因是:队列问题,动画执行情况是先进先出,前面的没完成,后面的就等着。
解决办法:后面来人了就把当前运行的动画停止了(每次执行slideDown/slideUp事件,先用stop()方法停止当前正在执行的动画)。。
建议:在jQuery中如果需要执行动画,建议在执行动画之前先调用stop方法,然后再执行动画。
//1.监听一级菜单的移入事件
$(".nav>li").mouseenter(function () {
//1.1拿到二级菜单
var $sub = $(this).children(".sub");
//t停止当前正在运行的动画
$sub.stop();
//1.2让二级菜单展开
$sub.slideDown(1000);
});
//2.监听一级菜单的移除事件
$(".nav>li").mouseleave(function () {
//1.1拿到二级菜单
var $sub = $(this).children(".sub");
//t停止当前正在运行的动画
$sub.stop();
//1.2让二级菜单收起
$sub.slideUp(1000);
});
5.7、jQuery淡入淡出动画
参数、注意事项和显示隐藏动画一模一样, 只不过动画效果不一样而已
1.fadeIn([s],[e],[fn])淡入动画
2.fadeOut([s],[e],[fn])淡出动画
3.fadeToggle([s,[e],[fn]])切换动画(显示变淡出,不显示变淡入)
4.fadeTo([[s],o,[e],[fn]])淡入到指定透明度动画
*{
margin: 0;
padding: 0;
}
div{
width: 300px;
height: 300px;
background: red;
display: none;
}
$(document).ready(function () {
$("button").eq(0).click(function () {
$("div").fadeIn(1000,function () {
alert("淡入完毕")
})
});
$("button").eq(1).click(function () {
$("div").fadeOut(1000,function () {
alert("淡出完毕")
})
});
$("button").eq(2).click(function () {
$("div").fadeToggle(1000,function () {
alert("切换完毕")
})
});
$("button").eq(3).click(function () {
$("div").fadeTo(1000,0.5,function () {
alert("淡入到完毕")
})
});
});
5.8、弹窗广告
$(".ad").stop().slideDown(1000).fadeOut(1000).fadeIn(1000);//动画队列,前面的执行后面的执行.加stop(),效果一样,但是规避隐藏bug
5.9、jQuery自定义动画
有时候jQuery中提供的集中简单的固定动画无法满足我们的需求, 所以jQuery还提供了一个自定义动画方法来满足我们复杂多变的需求
1).animate(p,[s],[e],[fn])
第一个参数:接受一个对象,可以在对象中修改属性
第二个参数:指定动画时长
第三个参数:指定动画节奏。默认swing:缓动(先慢后快再慢);linear:匀速。
第四个参数:动画执行完毕之后的回调函数。
$(".one").animate({
/*对象*/
marginLeft:500
},5000,"linear",function () {
});
2).每次开始运动都必须是初始位置或者初始状态,如果想在上一次位置或者状态下再次进行动画可以使用累加动画
$("button").eq(1).click(function () {
$(".one").animate({
width:"+=100"/*在过去的基础上累加100,100累加为200,再点累加变为300,依次类推*/
},1000,function () {
alert("自定义动画执行完毕");
});
});
动画还可以使用关键字进行操作
$("button").eq(2).click(function () {
$(".one").animate({
//width:"hide"
width:"toggle"/*有宽度的变为没有宽度,没有宽度的变为有宽度*/
},1000,function () {
alert("自定义动画执行完毕");
});
});
注意:{}中可以同时修改多个属性,多个属性的动画也会同时执行。
5.10、jQuery的stop和delay方法
1.在jQuery的对象{}中可以同时修改多个属性,多个属性的动画也会同时执行
$(".one").animate({
width:500,
height:500
},1000);
2.先执行宽度,再执行高度
$(".one").animate({
width:500,
//height:500
},1000);
$(".one").animate({
height:500
},1000);
3.链式编程,先执行宽度再执行高度
$(".one").animate({
width:500,
//height:500
},1000).animate({
height:500
},1000);
4.delay方法:用于告诉系统延迟时长
$(".one").animate({
width:500,
//height:500
},1000).delay(2000).animate({//执行完宽度等两秒再执行高度
height:500
},1000);
5.stop停止动画
$("button").eq(0).click(function () {
$(".one").animate({
width:500,
//height:500
},1000);
$(".one").animate({
height:500
},1000);
$(".one").animate({
width:100,
//height:500
},1000);
$(".one").animate({
height:100
},1000);
});
$("button").eq(1).click(function () {
//1.不传参数的:立即停止当前动画,继续执行后续的动画
$("div").stop();
//2.传参数false:立即停止当前动画,继续执行后续的动画
$("div").stop(false);
// 3.传参数false,false:立即停止当前动画,继续执行后续的动画
$("div").stop(false,false);
//4.传参数true:立即停止当前和所有后续动画。
$("div").stop(true);
//5.传参数true,false:立即停止当前和所有后续动画。
$("div").stop(true,false);
//6.传参数false,true:立即完成当前的,继续执行后续动画。
$("div").stop(false,true);
//7.传参数true,false:立即完成当前的,并且停止后续动画。
$("div").stop(true,true);
});
});
5.11、图标特效
5.12、无限循环滚动上
5.13、无限循环滚动下
六、jQuery节点操作(文件处理)
6.1、jQuery添加节点相关方法
内部插入
append(content|fn)
会将元素添加到指定元素内部的最后
appendTo(content)
作用同append,会将元素添加到指定元素内部的最后,区别是书写的格式不同,
prepend(content|fn)
会将元素添加到指定元素内部的最前面
prependTo(content)
作用同prepend,会将元素添加到指定元素内部的最前面,区别是书写的格式不同,
外部插入
after(content|fn)
会将元素添加到指定元素外部的后面。
before(content|fn)
会将元素添加到指定元素外部的前面。
insertAfter(content)
作用同after,区别在于书写方式不同
insertBefore(content)
作用同before,区别在于书写方式不同
$("button").click(function () {
//1.创建一个节点
var $li = $("
//2.添加节点
//内部插入
$("ul").append($li);//将li放到ul的最后,将要添加的节点作为参数。
$("ul").prepend($li);//将li放到ul的最前面
$li.appendTo("ul");//将要添加的元素作为调用者
$li.prependTo("ul");
//外部插入
$("ul").after($li);//将li放到ul外部的后面,紧跟ul之后添加
$("ul").before($li);//将li放到ul外部的前面
$li.insertAfter("ul");//将li放到ul外部的后面
$li.insertBefore("ul");//将li放到ul外部的前面
});
6.2、jQuery删除节点相关方法
remove([expr])
删除指定元素。
empty()
删除指定元素的内容和子元素,指定元素自身不会被删除。
detach([expr])
作用同remove。
$("button").click(function () {
$("div").remove();//找到谁删除谁
$("div").empty();
$("li").detach(".item");//删除所有li中有item类的li
});
我是段落
6.3、jQuery替换节点相关方法
replaceWith(content|fn)
替换所有匹配的元素为指定的元素。
replaceAll(selector)
作用同replaceWith,只是调用的顺序不同。
$("button").click(function () {
//1.新建一个元素
var $h6 = $("
//2.替换元素
$("h1").replaceWith($h6);
$h6.replaceAll("h1");
});
我是段落
6.4、jQuery复制节点相关方法
clone([Even[,deepEven]])
浅复制:传入false就是浅复制:clone(false),
深复制:传入true就是深复制:clone(true)。
浅复制和深复制的区别:
浅复制只会复制元素,不会复制元素的事件。
深复制会复制元素,而且还会复制元素的事件。
$("button").eq(0).click(function () {
//1.浅复制一个元素
var $li = $("li:first ").clone(false);//找到第一个li。
//2.将复制的元素添加到ul中
$("ul").append($li);
});
$("button").eq(1).click(function () {
//1.深复制一个元素
var $li = $("li:first ").clone(true);//找到第一个li。
//2.将复制的元素添加到ul中
$("ul").append($li);
});
$("li").click(function () {
alert($(this).html());
});
九、jQuery原理
9.1、jQuery基本结构
1.jQuery的本质是一个闭包
闭包:立即执行的函数
立即执行的函数:定义的同时就去执行
function test() {
console.log("test");
}
test();//不写这句调用函数,test函数不会执行。
上面的可以改写为
function test() {
console.log("test");
}();
此时定义的同时就去执行。就是立即执行的函数,就是闭包。
jquery的格式:
(function (w, undefined) {//使用w压缩
var jQuery = function () {
return new jQuery.fn.init();
}
w.jQuery = window.$ = jQuery;//将局部变量jQuery赋值给了全局变量
})(window);//接受window,传给框架的值
2.jQuery为什么使用闭包来实现
为了避免多个框架的冲突(变量名重复等问题)。因为变量写在函数中外界无法访问。
3.jQuery如何让外界访问内部定义的局部变量
window.xxx = xxx;
4.jQuery为什么要给自己传递window参数
- 为了方便后期压缩代码,将window简写为w后,内部不知道w是什么,因此需要给函数传进来window实参,表明w为window
- 为了提升查找的效率,自己有就找自己的,不用去外面找了。
5.jQuery为什么要给自己接受一个undefined参数?
为了方便后期压缩代码
IE9以下的浏览器undefined可以被修改,为了保证内部使用的undefined不被修改,所以需要接受一个正确的undefined
9.2、jQuery入口函数测试、
测试官方的jQuery入口函数传入不同参数得到的实例
1.传入 ‘’ null undefined NaN 0 false
console.log($());
console.log($(''));
console.log($(null));
console.log($(undefined));
console.log($(NaN));
console.log($(0));
console.log($(false));
会返回一个空的jQuery对象
2.传入html片段
会将创建好的DOM元素存储到jQuery对象中返回
console.log($("
1
2
3
"));3.传入选择器
会将找到的所有元素存储到jQuery中返回
console.log($("li"));
4.传入伪数组
会将数组中存储的元素依次存储到jQuery对象中返回
var Arr = {0:"1",1:"2",3:"3",length:3}
console.log($(Arr));
5.传入数组
会将数组中存储的元素依次存储到jQuery对象中返回
console.log($([1, 2, 3, 4, 5, 6]));
6.传入对象
会将传入的对象存储到jQuery对象中返回
function Person() {
console.log($(new Person()));
}
7.传入DOM元素(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.除上述类型以外
会将传入的数据存储到jQuery对象中返回
9.3、jQuery入口函数-代码片段实现
9.4、jQuery入口函数-工具方法抽取
//工具方法抽取
/*判断类型是否为string*/
njQuery.isString = function(str){
return typeof str === "string"
}
/*判断str是否是代码片段*/
njQuery.isHTML = function(str){
return str.charAt(0) == "<" && str.charAt(str.length - 1 ) ==">" && str.length >=3
}
/*去除代码片段两端(前部或后部)的空格*/
njQuery.trim = function(str){
//判断是否支持trim方法。IE9以下都不支持
if (str.trim){//如果支持就用trim处理
return str.trim();
} else {//如果不支持就用replace代替replace("找到的元素(也可使用正则表达式))","变为需要的元素")
//匹配开头的一个或多个空格,或者匹配结尾的一个或多个空格
//正则有个特点,找到了就不继续找了。如果找到开头的空格就不会接着找结尾的空格。解决办法:加g(全局匹配,找到了也接着找)
return str.replace(/^\s+ | \s+$/g,"")//\s:匹配空格 +:匹配多个 ^:匹配开头 $:匹配结尾 |:或 g:全局匹配
}
}
9.5、jQuery入口函数-代码片段优化
this:谁调用就是谁
/*
apply和call方法的作用:
专门用来修改方法内部的this
格式:
call(对象,参数1,参数2,...)
apply(对象,[数组])
*/
function test() {
console.log(this);//打印window。this是谁调用就是谁
}
//test();
var obj = {"name":"lnj" };
1.通过window.test找到test方法
2.通过apply方法将找的test内部的this改为自定义的对象obj
window.test.apply(obj);//打印 {"name":"lnj" }
window.test.call(obj);//打印 {"name":"lnj" }
验证call和apply的格式
function sum(a, b) {
console.log(this);
console.log(a + b);
}
window.sum.call(obj, 1, 2);//打印 {"name":"lnj" } 3
1.通过window.sum找到sum方法
2.通过apply(obj)方法将找的sum内部的this改为自定义的对象
3.将传入数组中的元素依次取出,传递给形参a、b
window.sum.apply(obj, [3, 5]);
// var arr = [];
// arr.push(1);//将1添加到arr数组中
// console.log(arr);
//将真数组转换伪数组的一个过程
var arr = [1, 3, 5, 7, 9];
var obj = {}
1.通过[].push找到数组中的push方法
2.通过apply(obj)将找到的push方法内部的this修改为自定义的对象
3.将传入数组arr中的元素依次取出,传递给形参
[].push.apply(obj, arr);//将arr中的数字依次取出来push给obj
console.log(obj);//{ 0:1,1:3,2:5,3:7,4:9,length:5 }
9.6、jQuery入口函数-真伪数组转换
伪数组:分为系统自带的伪数组,和我们自定义的伪数组。
window.onload = function (ev) {
//系统自带的伪数组
var res = document.querySelectorAll("div");//找到界面上所有的div,返回的对象res就是系统自带的伪数组。
console.log(res);//系统自带的伪数组
//自定义的伪数组
var obj = {0:"lnj", 1:"33", length:2};
//将定义好的伪数组转为真数组
var arr = [];//先定义一个真数组
[].push.apply(arr, res);//系统自带伪数组转换为真数组
[].push.apply(arr, obj);//自定义的伪数组转换为真数组,IE8以下的浏览器不可以(解决办法:IE8以下浏览器使用slice方法,并且不传参数)
console.log(arr);
var arr3 = [].slice.call(obj);//将内部的this改为自定义的伪数组obj,slice:将this中的每一个元素放到一个新的数组中原样返回
console.log(arr3);
//了解slice(截取数组的方法)
var arr2 = [1, 3, 5, 7, 9];
//如果slice方法什么参数都没有传递,会将数组中的元素放到一个新的数组中原样返回,直接返回[1, 3, 5, 7, 9];
// var res2 = arr2.slice();//[1, 3, 5, 7, 9];
// var res2 = arr2.slice(2);//从脚标2开始截取,结果为5,7,9
var res2 = arr2.slice(2, 4);//从脚标2开始截取,到脚标4为止,不包括脚标4,结果为5, 7
console.log(res2);
}
伪数组快速转换为真数组:[].slice.call(obj);
真数组快读转换为伪数组:[].push.apply(obj , arr);
9.7、jQuery入口函数-选择器处理
//2.2判断是否是选择器
else{
//1.根据传入的选择器找到对应的元素
var res = document.querySelectorAll(selector);//querySelectorAll系统提供给我们去做查询的,可以接受标签选择器,类选择器,id选择器等,可以根据传入的选择器找到对应的元素
console.log(res);
//2.将找到的元素添加到njQuery上
// for (var i = 0; i < res.length; i++){
// this[i] = res[i];
// }
// this.length = res.length;
[].push.apply(this, res);
//3.返回加工好的this
return this;
}
9.8、jQuery入口函数-数组处理
else if (typeof selector === "object" && "length" in selector && selector !== window){//真伪数组共同特点:都是对象,都有length属性,注意排除window。真数组.toString后,打印的是将数组内的数拼接为字符串,而伪数组.toString后打印[object object](toString:js的方法,将逻辑值转换为字符串)
//3.1 真数组
if (({}).toString.apply(selector) === "[object Array]") {
[].push.apply(this, selector);//真数组转为伪数组
return this;
//console.log("真数组");
}
//3.2 伪数组
else {
//console.log("是伪数组");
var arr = [].slice.call(selector);//自定义伪数组先转为真数组
[].push.apply(this, arr);//真数组转为伪数组
return this;
}
}
//以下部分为上面部分的优化
else if (njQuery.isArray(selector)){
//不管进来的是真伪数组,都先转为真数组
var arr = [].slice.call(selector);
//将真数组都保存在njQuery上
[].push.apply(this, arr);
//将加工好的njQuery返回
return this;
}
//上面的优化好的部分的工具类
/*判断是不是对象*/
njQuery.isObject = function(sele){
return typeof sele === "object";
};
/*判断是不是window*/
njQuery.isWindow = function(sele){
return sele === window;
};
/*判断是不是数组*/
njQuery.isArray = function(sele){
if (njQuery.isObject(sele) && !njQuery.isWindow(sele) && "length" in sele){
return true;//满足if中的要求说明是数组,返回true
}
return false;
};
9.9、jQuery入口函数-其它类型处理
// 4.除上述类型以外
else {
// 会将传入的数据存储到jQuery对象中返回
this[0] = selector;
this.length = 1;
// return this;
}
9.10、jQuery入口函数-extend方法(完全听不懂)
typeof function text(){}.将会返回function
也就是typeof一个函数,将会返回“function”
一个类中定义了很多方法,后期代码会难以维护,为了提高代码的可维护性,可以对方法进行分类管理。
jQuery分类管理方法:extend方法
向entend方法中传递的对象,这个和对象中是以key:value形式定义的方法。
extend( { key:value, key:value, key:value } );
将相同类型的方法放到一个对象当中,传递给extend
9.11、jQuery入口函数-函数处理
对传入的方法类型进行特殊处理,类jQuery传入方法类型时,判断DOM元素是否加载完毕。加载完毕可执行函数。
jQuery中使用ready方法,监听DOM是否加载完毕,
onload是原来js来判断DOM是否加载完毕的方法,如果加载完毕执行回调函数function
而jQuery不适用onload方法,因为onload方法性能不好。
window.onload = function (ev) {
var res = document.querySelectorAll("div");
console.log(res);
console.log("onload");
}
onload会等到界面上所有DOM元素加载完毕,并且等相关资源也加载完毕才会执行。
js的DOMContentLoaded事件只会等到DOM元素加载完毕就会执行回调
document.addEventListener("DOMContentLoaded",function () {//添加事件监听,监听之后可以绑定回调。
var res = document.querySelectorAll("div");
console.log(res);
console.log("DOMContentLoaded");
})
判断onload,DOMContentLoaded谁快:同时打印log,谁快先显示谁
问题:addEventListener监听事件只支持高级浏览器,不支持低级浏览器(IE8及以下)。可以使用attachEvent方法,同时IE8及以下也没有DOMContentLoaded事件。
解决兼容问题的办法:
document.readyState属性有如下的状态
uninitialized - 还未开始载入
loading - 载入中
interactive - 已加载,文档与用户可以开始交互
complete - 载入完成
onreadystatechange事件就是专门用于监听document.readyState属性的改变
document.attachEvent("onreadystatechange", function () {
var res = document.querySelectorAll("div");
console.log(res);
if (document.readyState == "complete"){
//加载完毕
console.log("readystatechange");
}
});
整体代码:
ready:function (fn) {//接收回调
//判断DOM是否加载完毕,如果加载完毕执行回调fn
if(document.readyState == "complete"){//加载完成
fn();
}
else if (document.addEventListener){//高级浏览器 支持addEventListener
document.addEventListener("DOMContentLoaded",function () {//添加事件监听,监听之后可以绑定回调。
fn();
})
}
else {//低级浏览器 不支持addEventListener
document.attachEvent("onreadystatechange", function () {
if (document.readyState == "complete"){
fn();
}
});
}
},
9.12、jQuery原型上的属性
以上是jQuery核心函数,下面介绍jQuery原型上的其他属性和方法。
1-6:属性;7-11:方法
1、jquery:获取jq版本号。jquery: "1.0.0",
2、selector:实例默认的选择器取值(默认选择器,为空) selector:"",
3、length:实例默认的长度 length: 0,
4、push:给实例添加新元素(数组的方法) push: [].push,
[].push:找到数组的push方法
冒号前面的push将来由njQuery对象调用,this就是njQuery对象
push: [].push,这句话相当于[].push.apply(this);即将push内部的this替换为了njQuery对象
5、sort:对实例中的元素进行排序(数组的方法) sort: [].sort,
6、splice:按照指定下标指定数量删除元素,也可以替换删除的元素(数组的方法)
splice: [].splice,
7、toArray:把实例(jQuery对象、伪数组)转化为真数组返回
toArray: function () {
return [].slice.call(this);
},
8、get:获取指定下标的元素,获取的是原生DOM
什么都不传相当于toArray,返回数组
传递正数,返回元素
传递负数:返回第 负数 + length的元素
9、eq:获取指定下标的元素,获取的是jQuery类型的实例对象
eq与get方法类似,但区别是eq返回的是包装好的jQuery对象,get方法返回的是原生的DOM元素
什么都不传,返回空的jQuery
传递正数,返回jQuery
传递负数:返回第 负数 + length的jQuery
10、first:获取实例中的第一个元素,是jQuery类型的实例对象。相当于eq(0)
11、last:获取实例中的最后一个元素,是jQuery类型的实例对象。相当于eq(-1)
12、each:遍历实例,把遍历到的数据传给回调使用
原生forEach:只能遍历真数组
obj.forEach(function(value, index){
});
jQuery的each:真伪数组(for循环遍历)、对象(for in循环 )都能遍历
obj.each(function(index, value ){
console.log(this);//this为value
});
obj.map(function(value, index){
console.log(this);//this为value
});
13、map:遍历实例,把遍历到的数据传给回调使用,然后把回调的返回值收集起来组成一个新的数组返回
each和map方法的区别:
each默认遍历谁就返回谁
map默认的返回值是一个空数组
each不支持在回调函数中对遍历的数组进行处理
map可以在回调函数中通过return对遍历的数组进行处理(加减乘除)。
9.13、jQuery原型上的方法-toArray和get
9.14、jQuery原型上的方法-eq和first-last
9.15、jQuery原型上的方法-each方法
原生forEach只能遍历真数组,不能遍历伪数组。each可以遍历数组,伪数组和对象。
jQuery官方文档中有核心函数,和工具类两种。具体实现时,先实现工具方法,再在核心函数each中调用工具方法。
each: function (obj, fn) {
//1.判断是否是数组
if (njQuery.isArray(obj)){
for (var i = 0; i fn(i, obj[i]);//i:索引 } } //1.判断是否是对象 else if (njQuery.isObject(obj)){ for (var key in obj){ fn(key, obj[key]); } } } //each方法 var arr = [1, 3, 5, 7, 9]; var obj1 = {0: "inh", 1: "33", 2: "", length:3}; var obj2 = {"name": "inj", "age": "3"}; njQuery.each(obj2,function (key, value) { console.log(key, value); }); 9.16、jQuery原型上的方法-each方法细节处理 9.17、jQuery原型上的方法-map方法 map: function (obj, fn) { var res = []; //1.判断是否是数组,如果是数组用普通for循环遍历 if (njQuery.isArray(obj)){ for (var i = 0; i < obj.length; i++){ var temp = fn(obj[i], i);//执行回调函数,将遍历的结果返回给它,map先返回value再返回key if (temp){ res.push(temp); } } } //2.判断是否是对象,如果是对象就用for in循环进行遍历 else if (njQuery.isObject(obj)){ for (var key in obj){ var temp = fn(obj[key], key); if (temp){ res.push(temp); } } } return res; } var res = njQuery.map(arr, function (value, key) { // console.log(value, key); if (key === 2){ return value; } }) console.log(res); 9.18、jQueryDOM操作相关方法-empty方法 DOM操作: 1、empty:清空指定元素中的所有内容 2、remove:删除所有的元素或指定元素 3、html:设置所有元素的文本内容,获取第一个元素的内容 4、text:设置所有元素的文本内容,获取所有元素的文本内容 5、appendTo:将元素添加到指定元素内部的最后 6、append:将元素添加到指定元素内部的最后 7、prependTo:将元素添加到指定元素内部的最前面 8、prepend:将元素添加到指定元素内部的最前面 9、insertAfter:将元素添加到指定元素外部的后面 10、after:将元素添加到指定元素外部的后面 11、insertBefore:将元素添加到指定元素外部的前面 12、before:将元素添加到指定元素外部的前面 13、replaceAll:替换所有指定元素 14、replaceWith:替换所有指定元素 15、clone:复制节点(true深复制,false浅复制) empty: function () { //1.遍历所有找到的元素 this.each(function (key, value) { value.innerHTML = ""; }) //2.调用empty后返回jQuery实例,谁调用返回谁。 // return this是为了方便链式编程 return this; }, 9.19、jQueryDOM操作相关方法-remove方法(听不懂) remove: function (sele) { if (arguments.length === 0){//remove没有传递参数,删除所有(arguments对象在函数中引用函数的参数。) //1.遍历所有指定的元素 this.each(function (key, value) { //删除元素,元素不能删除自己,只能通过自己找到父元素,然后再通过父元素删除它自己 //根据遍历到的元素找到对应的父元素(parentNode:属性) var parent = value.parentNode; //通过父元素删除指定的元素 parent.removeChild(value)//指定的元素为value }); }else{//remove传递了参数 var $this = this; //1.根据传入的选择器找到对应的元素(class类型.box) $(sele).each(function (key, value) { //2.遍历找到的元素,获取对应的类型 var type = value.tagName;//查看.box元素的标记名称,html名称 //3.遍历指定的元素 $this.each(function (k, v) { //4.获取指定元素的类型 var t = v.tagName;//获取class为.box的元素的标记名称(html是div,p还是其他) //5.判断找到元素的类型和指定元素的类型 if (t === type){ //根据遍历到的元素找到对应的父元素 var parent = value.parentNode; //通过父元素删除指定的元素 parent.removeChild(value)//指定的元素为value } }); }) } return this;//返回对象,方便链式编程 }, 9.20、jQueryDOM操作相关方法-html方法 html:设置所有元素的文本内容,获取第一个元素的内容 html: function (content) { //没传递参数,将第0个元素返回 //传递参数,将文字内容替换为参数 if (arguments.length === 0){ return this[0].innerHTML;//返回第0个元素对应的内容 } else{ this.each(function (key, value) { value.innerHTML = content;//将遍历到的innerHTML值修改为传入的值 }) } }, 9.21、jQueryDOM操作相关方法-text方法 text:设置所有元素的文本内容,获取所有元素的文本内容 text: function (content) { //判断是否传入参数 if (arguments.length === 0) { //没有传入参数,返回所有元素 var res = "";//定义空字符串 this.each(function (key, value) { res += value.innerText;//将每次拿到的内容,拼接到res上 }) return res; }else{ //传入参数,将所有内容改为指定的参数 this.each(function (key, value) { value.innerText = content; }) } } 9.22、jQueryDOM操作相关方法-appendTo方法上 appendTo:将元素添加到指定元素内部的最后,返回值为所添加元素的jQuery对象 1、可以接受字符串 2、可以接受jQuery对象(jQuery本质是伪数组) 3、可以接受DOM元素 以上三种数据类型可以统一处理,处理方法: 将这三种数据类型放入jQuery的核心函数中,转换为同一种数据类型jQuery appendTo: function (sele) { //1、将传入的数据传给核心函数,统一转换为jQuery类型 var $target = $(sele); var $source = this;//需要添加的元素 var res = [];//用于存储source //1.遍历取出所有指定的元素 $.each($target, function (key, value) { // var targetEle = value;//优化,注释掉 //1.1.遍历取出所有的元素 $source.each(function (k, v) { // var sourceEle = v;//优化,注释掉 //1.2.判断当前是否是第0个指定的元素 if (key === 0){ //如果是第一个元素0直接添加source value.appendChild(v);//将source传入 res.push(v); }else{ //其他的目标元素,先copysource再添加 var temp = v.cloneNode(true);//赋值source和内部内容 value.appendChild(temp); res.push(temp); } }) }); //2.返回所有添加的元素 return $(res);//整体循环完成后将res转换为jQuery对象,返回。 }, 9.23、jQueryDOM操作相关方法-appendTo方法下 9.24、jQueryDOM操作相关方法-prependTo方法 同appendTo 9.25、jQueryDOM操作相关方法-append方法 appendTo和append区别 1.参数和调用者顺序不同 2.对参数字符串处理的方法不同 appendTo:会将字符串当做选择器来处理。 append:不会将字符串当做选择器来处理。 3.返回值不同 appendTo:将所有添加的元素添加到数组中,并将数组包装为jQuery对象返回。 append:直接将调用者返回,在内部直接返回this。 9.26、jQueryDOM操作相关方法-prepend方法 9.27、jQueryDOM操作相关方法-insertBefore方法 prependTo同insertBefore的区别: prependTo:将元素插入到指定元素内部部之前 insertBefore:将元素插入到指定元素外部之前 重要代码原理: 找到target的老爹,将source插入到老爹的第一个元素之前*/ //1.拿到指定元素的父元素 var parent = target.parentNode; //2.利用指定元素的父元素来调用原生js的insertBefore方法 /* 调用者div.insertBefore(插入的元素p, 参考的元素); 将p插入到div内部第一个元素之前 insertBefore方法:调用者是谁就会将元素插入到谁里面 */ 其余方法: (作业)next和prev的实现,需要使用原生js的nextSibling属性和previousSibling属性 next(); 获取紧邻的后面同辈元素的元素 prev(); 获取元素紧邻的前一个同辈元素 insertAfter和after的实现,需要使用原生js的nextSibling属性 (作业)元素.insertAfter.指定元素——将元素添加到指定元素外部的后面 (作业)指定元素.after.元素——将元素添加到指定元素外部的后面 (作业)指定元素.before.元素——将元素添加到指定元素外部的前面 9.28、jQueryDOM操作相关方法-replaceAll方法 元素.replaceAll.指定元素——替换所有指定元素 (作业)指定元素.replaceWith.元素——替换所有指定元素 9.29、jQuery属性操作方法-attr方法 1.attr():设置或者获取元素的属性节点值 2.prop():设置或者获取元素的属性值 3.css():设置或者获取元素样式 4.val():设置或者获取value属性节点的值 5.hasClass():判断有没有指定类 6.addClass():给所有元素添加指定类或者所有类 7.removeClass():清空所有元素指定类或者所有类 8.toggleClass():有则删除,没有则添加 attr:function (attr, value) { // 1.判断是否是字符串 if(njQuery.isString(attr)){ // 判断是一个字符串还是两个字符串(参数个数) if (arguments.length === 1){ // 返回jQuery对象的第0个元素的属性节点值 return this[0].getAttribute(attr); }else{ // 遍历对象,将所有存储的DOM元素取出,将每个DOM元素对应的属性节点的值都修改了 this.each(function (key, ele) { ele.setAttribute(attr, value); }) } } // 2.判断是否是对象 else if (njQuery.isObject(attr)){ var $this = this; // 遍历对象中所有属性节点的名称和对应的值 $.each(attr, function (key, value) { // 遍历取出所有jQuery对象,取出所有DOM元素 $this.each(function (k, ele) { ele.setAttribute(key, value); }) }) } return this; } 9.30、jQuery属性操作方法-prop方法 2.prop():设置或者获取元素的属性值 传递两个参数,代表设置所有元素属性值,并且返回值就是方法调用者 console.log($("span").prop("abc", "abc")); 传递一个参数,返回第一个元素属性值 console.log($("span").prop("abc")); 传递一个对象,代表批量设置所有元素属性值 $("span").prop({//对象 "aaa":"888", "bbb":"cc" }); prop:function (attr, value) { // 1.判断是否是字符串 if(njQuery.isString(attr)){ // 判断是一个字符串还是两个字符串(参数个数) if (arguments.length === 1){ // 返回jQuery对象的第0个元素的属性节点值 return this[0][attr]; }else{ // 遍历对象,将所有存储的DOM元素取出,将每个DOM元素对应的属性节点的值都修改了 this.each(function (key, ele) { ele[attr] = value; }) } } // 2.判断是否是对象 else if (njQuery.isObject(attr)){ var $this = this; // 遍历对象中所有属性节点的名称和对应的值 $.each(attr, function (key, value) { // 遍历取出所有jQuery对象,取出所有DOM元素 $this.each(function (k, ele) { ele[key] = value; }) }) } return this; } 9.31、jQuery属性操作方法-css方法 3.css():设置或者获取元素样式 9.32、jQuery属性操作方法-val方法 4.val():设置或者获取value属性节点的值 不传递参数,返回第一个元素属性节点的value值 console.log($('input').val()); 传递参数,代表设置所有元素属性节点的value值,返回值就是方法的调用者 console.log($('input').val('new value')); val:function (content) { // 1.判断有没有传参 if (arguments.length === 0){ // 没传参:获取value属性节点的值 return this[0].value; } else{ // 传参:传参value属性节点的值 this.each(function (key, ele) { ele.value = content; }); return this; } } 9.33、jQuery属性操作方法-hasClass方法 5.hasClass():判断有没有指定类 不传递参数,返回false console.log($('div').hasClass()); 传递参数,多个调用者,只要其中一个包含指定类就返回true,否则返回false console.log($('div').hasClass('cc')); console.log($('div').hasClass('sd')); /*js分析 var div = document.querySelector("div"); //使用getAttribute获取属性节点和className获取属性值两种方法取得的值一模一样 console.log(div.getAttribute("class"));//获取属性节点 console.log(div.className);//获取属性值 // 1.获取元素中class保存的值,并且给前后加上空格 var className = div.className; // 2.通过indexOf判断是否包含指定的字符串 // console.log(className.indexOf("bb") != -1);//存在返回true,不存在返回false // console.log(className.indexOf("bb"));//打印2 问题:会找到aabb的“bb” // console.log(className.indexOf(" " + "cc" + " "));//打印4 问题:第一个类名和最后一个类名没用空格.解决办法:获取字符串的时候给字符串的前后加空格 className = " " + div.className + " "; console.log(className.indexOf(" " + "bb" + " "));//打印8 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; } }, 9.34、jQuery属性操作方法-addClass方法 6.addClass():给所有元素添加指定类或者所有类 不传递参数,返回this console.log($('div').addClass()); 传递参数,如果元素中没有指定的类就添加,有就不添加,返回this便于链式编程 console.log($('div').addClass('cc')); console.log($('div').addClass('sd aabb sdf')); addClass:function (name) { if (arguments.length === 0) return this; // 1.对传入的类名进行切割 var names = name.split(" "); // 2.遍历取出所有要添加类的元素 this.each(function (key, ele) { // 3.遍历数组names,取出每一个类名 $.each(names, function (k, value) { // 4.判断拿到的元素ele,是否包含指定的类value if (!$(ele).hasClass(value)){//将ele包装为对象,看对象中是否包含类名value,包含了hasClass会返回true ele.className = ele.className + " " + value; console.log($(ele), value, $(ele).hasClass(value)); } }) }); return this; } 9.35、jQuery属性操作方法-removeClass方法 7.removeClass():清空所有元素指定类或者所有类 不传递参数,删除所有类 console.log($('div').removeClass()); 传递参数,如果元素中没有指定的类什么都不做,有就删除,返回this便于链式编程 console.log($('div').removeClass('cc')); console.log($('div').removeClass('sd aabb sdf')); removeClass:function (name) { if (arguments.length === 0){ // 将所有元素的className设置为空 this.each(function (key, ele) { ele.className = ""; }) }else{ // 对传入的类名进行切割 var names = name.split(" "); // 遍历取出所有元素 this.each(function (key, ele) { $.each(names,function (k, value) { if ($(ele).hasClass(value)){ //“ abc cc” replace(" abc ", ""); ele.className = (" " + ele.className + " ").replace(" "+value+" ", ""); } }) // 取出类名,有就删除,没有就不管 }) } return this; } 9.36、jQuery属性操作方法-toggleClass方法 8.toggleClass():有则删除,没有则添加 不传递参数,删除所有类 console.log($('div').toggleClass()); 传递参数,如果元素中没有指定的类就添加类,有就删除,返回this便于链式编程 console.log($('div').toggleClass('cc')); console.log($('div').toggleClass('sd aabb sdf')); toggleClass:function (name) { if (arguments.length === 0){ this.removeClass(); }else{ // 对传入的类名进行切割 var names = name.split(" "); // 遍历取出所有元素 this.each(function (key, ele) { $.each(names,function (k, value) { if ($(ele).hasClass(value)){//有,就删除类名 $(ele).removeClass(value); }else{// 没有就添加类名 $(ele).addClass(value); } }) // 取出类名,有就删除,没有就不管 }) } return this; } 9.37、jQuery事件操作相关方法-on方法上 on(type, callback):注册事件 注册多个相同类型事件,后注册的不会覆盖先注册的 注册多个不同类型事件,后注册的不会覆盖先注册的 高级、低级浏览器中都是先注册的先执行 高级版本浏览器支持addEventListener,低级浏览器不支持,需要使用attachEvent(高级浏览器不支持) 兼容性写法: function attachEvent(dom, name, callBack) { if (dom.addEventListener) { dom.addEventListener(name, callBack); }else{ dom.attachEvent("on"+name, callBack); } } attachEvent(btn, "click", function () { alert("buttonC"); }) 9.38、jQuery事件操作相关方法-on方法中 解决注册事件先后顺序(要求先注册先执行)问题(高级浏览器先注册先执行,低级浏览器先注册不一定先执行 ) 逻辑较为复杂,看代码吧 function addEvent(dom, name, callBack) { /*第一次:btn, "click", test1*/ /*第三次:btn, "mouseenter", test3*/ /*第四次:btn, "mouseleave", test4*/ if (!dom.eventsCache){ dom.eventsCache = {};//btn.eventsCache = {}; } /*eventsCache:解决注册事件先后顺序(要求先注册先执行)问题(高级浏览器先注册先执行,低级浏览器先注册不一定先执行 )*/ // if (!dom.eventsCache){//1.第一次:btn没有eventsCache属性,需要添加 if (!dom.eventsCache[name]){//1.第一次:btn没有eventsCache对象中有没有叫click的属性,没有属性需要添加 // dom.eventsCache = [];//2.给dom添加eventsCache属性 /* btn.eventsCache = { click:[] }; * */ dom.eventsCache[name] = [];//2.给dom添加eventsCache对象的click属性 // dom.eventsCache.push(callBack);// 3.btn.eventsCache = [test1]; /* 3.btn.eventsCache = { click:[test1] }; * */ dom.eventsCache[name].push(callBack); /*解决注册事件,高级、低级浏览器的兼容问题(高级支持addEventListener,不支持attachEvent,低级浏览器反之)*/ if (dom.addEventListener) {//6.点击页面按钮执行注册的click事件 dom.addEventListener(name, function () { for (var i = 0; i < dom.eventsCache[name].length; i++){ // dom.eventsCache[i]();//7.第一次:test1() 8.第二次:test2() dom.eventsCache[name][i]();//区分开了不同事件,不同类型的事件分别按照顺序执行 } }); }else{ dom.attachEvent("on"+name, function () { for (var i = 0; i < dom.eventsCache[name].length; i++){ dom.eventsCache[name][i](); } }); } } /*第二次:btn, "click", test2*/ else{//4.第二次:btn有eventsCache对象的click属性了 // dom.eventsCache.push(callBack);//5.btn.eventsCache = [test1, test2]; /* 5.btn.eventsCache = { click:[test1,test2] };*/ dom.eventsCache[name].push(callBack); } } function test1(){ alert("click1"); } function test2(){ alert("click2"); } function test3(){ alert("mouseenter"); } function test4(){ alert("mouseleave"); } addEvent(btn, "click", test1); addEvent(btn, "click", test2); addEvent(btn, "mouseenter", test3); addEvent(btn, "mouseleave", test4); 9.39、jQuery事件操作相关方法-on方法下 封装进jQuery框架。 9.40、jQuery事件操作相关方法-off方法 off(type, callback):移除事件 1.不传参,移除所有事件 == btn.eventsCache = {} 2.传一个参,移除对应类型所有事件 == btn.eventsCache = {click:[],mouseenter:[test3] 3.传两个参,移除对应类型对应事件 == btn.eventsCache = {click:[test2],mouseenter:[test3] 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] = []; }); } // 2.判断是否传入了两个参数 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);//splice从当前遍历到的位置,向后删除一个 } }); // ele.eventsCache[name] = []; }); } return this; } 9.41、jQuery事件操作相关方法-clone方法 复制节点——true:深复制;flase:浅复制 jQuery浅复制为复制元素及内容 jQuery深复制为复制元素、内容及事件 原生的js的深复制浅复制是使用cloneNode(true为深复制可以复制元素和内容,但是不可以复制事件)。因此没有原生js可以实现对事件的复制。需要使用jQuery中的eventsCache属性来实现。 clone:function (deep) { var res = []; // 判断是否是深复制 if (deep){//如果为真,就是深复制 this.each(function (key, ele) { // cloneNode:原生js,true为深复制可以复制元素和内容,但是不可以复制事件 var temp = ele.cloneNode(true); // 遍历元素中的eventsCache属性,因为eventsCache中保存着所有类型的事件 njQuery.each(ele.eventsCache, function (name, array) { // 遍历事件对应的数组 njQuery.each(array, function (index, method) { // 给复制的元素添加事件 $(temp).on(name, method); }); }); // 将复制的元素temp,返回给调用者使用 res.push(temp); }); return $(res); }else{ // 浅复制 this.each(function (key, ele) { // cloneNode:原生js,true为深复制可以复制元素和内容,但是不可以复制事件 var temp = ele.cloneNode(true); // 将复制的元素temp,返回给调用者使用 res.push(temp); }); return $(res); } }