jQuery:JavaScript library —— John Resig 2006-8-26
一般公司对交互性要求没那么高的时候,PC用1.x版本,移动端用2.x版本
jQuery cdn cdn.bootcdn.net/ajax/libs/j…
压缩工具:雅虎YUI Compressor、Google JavaScript Closure Compiler
js压缩除了会把换行空格注释去掉,还会修改变量名,缩短变量名以减小文件大小
混淆会修改变量名和函数名为毫无意义的命名,防窃取
jQuery === $
基础语法
选择器
选择器写法和css基本一致
| 选择器 | 说明 |
|---|---|
| .class/#id/tag | |
| .wrapper ul | 父子选择器 |
| li: first | |
| li: odd/even | 奇数/偶数,从0开始 |
| li: eq(num) | 选择第几个,从0开始,-1从最后一个开始,num写999不会执行也不会报错,因为jQuery有容错机制 |
| li[data='first'] | 选属性名为data值为first的属性 |
| li[data$='th'] | 选择值以th结尾的data属性 |
| li[data^='f'] | 选择值以f开头的data属性 |
| li[data!='f'] | 选择值不是f的data属性,包含f不算 |
获取元素有两种方法
var one = $('ul li');
var two = $('li', 'ul'); //两个参数,第二个参数是第一个参数的上下文
容错机制:(undefined)……不会报错,不会阻止程序运行,这样做其实是非常好的
例:
$('li').each(function(index, elem){
$(elem).find('.icon').css({fontSize: '12px', color: 'red'}};
})
这里循环找li里的icon,如果不是每一个li都有icon,也是不会报错的,找不到就算了(容错机制),在原生JS中有一个找不到就会报错
简单重写源码
要实现的目标:
- $() JQ对象
- jQuery.fn.init 用构造函数实现
- 封闭作用域
;(function() {
function jQuery(selector) {
//通过这个函数调用,传入参数,执行init函数,由于init是构造函数,再new实例化一下
return new jQuery.prototype.init(selector);
}
jQuery.prototype.init = function(selector) {
// this = {}; init函数实例化出来this
// 按照相应的选择器,找到对应的DOM元素,包装成jQuery对象并返回
this.length = 0;
if (selector.indexOf('.') != -1) {
var elem = document.getElementsByClassName(selector.slice(1));//slice去点
} else if(selector.indexOf('#') != -1) {
var elem = document.getElementById(selector.slice(1));
}
// 只选出来一个元素的情况下,elem是不会有长度的,没有长度执行下面的循环就会报错
if (elem.length === undefined) {
this[0] = elem;
this.length ++;
}
for (var i = 0; i < elem.length; i++) {
this[i] = elem[i];
this.length ++;
}
}
// css方法不在jQuery.prototype.init里面,无法调用
jQuery.prototype.init.prototype = jQuery.prototype;
jQuery.prototype.css = function(option) {
for (var i = 0; i < this.length; i++) {
// this就是init实例化出来的this,里面包含选出来的元素
for(var attr in option) {
this[i].style[attr] = option[attr];
}
}
return this; //实现链式调用
}
window.$ = window.jQuery = jQuery;
})();
$('#logo').css({width: '300px', height: '300px'})
.css({opacity: .2});
没有将元素添加到this对象的话,打印出来的仅仅是原生选出来的类数组
添加了之后
$(document).ready
DOM元素加载完成
$(document).on("ready", function() {...})
$(document).ready(function() {...})
$(function() {...})
window.onload不仅是DOM元素加载完成,还会等img加载完成,对应jQuery:
$(window).on("load", function() {...})
$(window).load(function() {...})
DOM元素加载完成就可以绑定事件了,但是在一些场景下还是要用window.onload,比如说轮播图需要用到图片的宽高,图片没加载玩没法做
选择查找
get
$()获取的是jQuery对象,是类数组;get方法获取到的是原生的js对象
$('li').get()
不传参数、传null、undefined返回的是所有的li元素,传参就是第几个(从0开始)
jQuery.prototype.get = function(number) {
// if (number == null) {
// return [].slice.call(this, 0);
// } else {
// if (number >= 0) {
// return this[number];
// } else {
// // 负数就数字+长度
// return this[number + this.length];
// }
// }
return number != null
? (number >= 0 ? this[number] : this[number + this.length])
: [].slice.call(this, 0);
}
eq
和get最大的区别就是eq返回的是jQuery对象(类数组)
为什么有了eq选择器还有eq方法呢?
因为eq选择器没有办法做到先统一给所有类添加方法,再单独添加方法
$('.demo').css({'color': 'red'}).eq(3).css({'color': 'blue'});
$('.demo:eq(3)').css({'color': 'red'}).css({'color': 'blue'});
没传参返回空,其他用法和get一样
修改源码
jQuery.prototype.init = function(selector) {
this.length = 0;
if (selector == null) {
return this;
}
if (typeof selector == 'string' && selector.indexOf('.') != -1) {
var elem = document.getElementsByClassName(selector.slice(1));
} else if(typeof selector == 'string' && selector.indexOf('#') != -1) {
var elem = document.getElementById(selector.slice(1));
}
// 原生DOM对象,eq只会选一个
// if (selector instanceof Element) {
// this[0] = selector;
// this.length++;
// }
// 只选出来一个元素的情况下,elem是不会有长度的,没有长度执行下面的循环就会报错
// if (elem.length === undefined) {
// this[0] = elem;
// this.length ++;
// }
if (selector instanceof Element || elem.length === undefined) {
this[0] = elem || selector;
this.length ++;
}
for (var i = 0; i < elem.length; i++) {
this[i] = elem[i];
this.length ++;
}
}
jQuery.prototype.eq = function(number) {
var elem = number != null
? (number >= 0 ? this[number] : this[number + this.length])
: [].slice.call(this, 0);
return jQuery(elem); //数组变成类数组
}
find
在原有的基础上进行查找子元素
$('ul').css({'color': 'blue'});
.find('li').css({'color': 'yellow'});
prevObject可以查看通过方法找到的元素的上一级,比如li的prevObject是ul,ul(顶级)的prevObject是document。如果在HTML里ul还有上一级的话是不会认的。
jQuery是建立在原生JS的基础上的,最开始就是document.get……
过滤筛选
filter
<div class="container">
<ul>
<li>1</li>
<li class="special-item">2</li>
<li class="special-item">34</li>
</ul>
</div>
找到container下面的special-item
$('.container ul').find('li').filter('.special-item');
要注意的是不能在ul上filter,要先选出来一个集合,再filter
和直接用find找到special-item的区别是prevObj不一样
filter还可以传特殊的选择器和函数
$('.container ul').find('li').filter(':even')
$('.container ul').find('li').filter(function(idx, elem) {
console.log(idx, elem); //this指向elem
return idx % 2 == 0;
})
not 和filter相反
和filter结果相反,filter返回的是满足条件的元素,not是返回不满足条件的元素
源码涉及到Sizzle.js —— jQuery选择器引擎
has 拥有某个子元素的元素
方便查找元素
<ul>
<li>
<ul>
<li></li>
<li></li>
<li></li>
</ul>
</li>
<li></li>
<li></li>
</ul>
$('li').has('ul');
查找有ul的li元素
is 返回布尔值
判断选出来的元素是否某个标签
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
$('ul').click(function(e) {
conaole.log(e.target); //原生DOM对象,要使用的话需要转换
if($(e.target).is('li')){
console.log($(e.target).text());
} else {
console.log($(this).text());
}
})
add 集中操作
$('ul').css({'color': 'green'})
.find('li').css({'color': 'green'})
如果不用add的话,想要给li继续地集体添加样式就需要通过find找到所有的li
$('ul').add('li').css({'color': 'green'})
等效第一种写法,ul和li都会加上相同的样式
可以看到第0项多出来父元素li,所以这个方法会新创建一个jQuery实例对象
如果HTML的其他部分也有一样的结构,也会选上
<div id="logo">
<ul>
<li></li>
<li></li>
<li></li>
</ul>
</div>
<ul>
<li></li>
<li></li>
<li></li>
</ul>
console.log($('#logo ul').add('li').css({'border': '1px solid black'}));
是个li都会被加上
jQuery.prototype.add = function(selector) {
var curObj = jQuery(selector),
baseObj = this,
newObj = jQuery(); //空对象
for (var i = 0; i < curObj.length; i++) {
newObj[newObj.length++] = curObj[i];
}
for (var i = 0; i < curObj.length; i++) {
newObj[newObj.length++] = baseObj[i];
}
this.pushStack(newObj);
return newObj;
}
end 回退
jQuery操作
$('ul').css({...})
$('ul').find('li').css({...})
这两个css操作基于的对象是不一样的。如果你用了li之后又想回到ul,就可以使用end
$('ul').css({'border': '1px solid black'})
.find('li').css({'border': '1px solid red'})
.end().css({'border': '1px solid green'});
回退之后返回的新的jQuery对象就是prevObject里的内容
源码实现:
end是靠prevObject实现回退的,很多函数都需要有这个属性,所以抽象一个函数
jQuery.prototype.pushStack = function(elem) {
if (elem.constructor != jQuery) {
elem = jQuery(elem);
}
elem.prevObject = this;
return elem;
}
jQuery.prototype.end = function() {
return this.prevObject;
}
获取内容
html
html相当于innerHTML
<div id="logo">
<ul id="list">
<li class="item">1</li>
<li class="item">2</li>
<li class="item">3</li>
</ul>
</div>
$('div').html()
如果是一个集合使用这个方法,只会读取第一个元素的html(特例)
$('div ul li').html() //1
和css方法不同,css方法会循环操作这个集合
但是赋值操作是可以替换集合里的所有元素的,要特别注意取值和赋值得到的元素不同
$('div ul li').html('<span>替换后的内容</span>')
还可以操作数组
var arr = ['Jackson', 'Daniel', 'Eden'];
$('div ul li').html(function(idx, elem) {
return '<span>' + arr[idx] + '</span>';
})
text
只会打印文本内容,和innerText一样,一个集合取值会获得所有元素的文本,和html不一样
同样可以赋值和操作数组
size() 相当于length
操作class
addClass
$('div ul li').eq(1).addClass('active warning');
空格jQuery会自动帮你加,不需要在active前面空格,当然你添加多个类名,之间还是要有空格的
$('div ul li').addClass('active warning');
集合添加类名是会循环操作的,也就是说所有li都会添加类名
还可以操作方法
$('div ul li').addClass(function(idx, elem) {
return 'item-' + idx;
})
并且可以灵活的进行条件判断
$('div ul li').addClass(function(idx, elem) {
if ((idx + 1) % 2 != 0) {
return 'active';
}
})
removeClass
操作和addClass相同,可以循环删除集合上的类名和传方法
jQuery有非常高的容错机制,如果你删除一个不存在的类名或者传入空串,什么都不会发生;如果删除的多个类名排列顺序和html里的不一致,也没有关系,还是会删除;如果你什么都不传,就会把类名全删了。
$('div ul li').click(function(e) {
$('.item').removeClass('active');
$(this).addClass('active');
});
最好不要用css操作,而是通过类添加,原因如下:
- 维护
- 复用性
- css文件是可以缓存的
hasClass
即使你一个元素有多个类名,只要包含要找的类名,也会返回true
css
赋值
$('div').css('color', 'blue');
$('ul').css({'backgroundColor': 'green', 'border': '1px solid yellow'})
.css('width', '+=100px');
可以在原有的基础上+=
取值
$('div').css('color');
取值取颜色的话,返回rgb
属性相关
attr
取值
$('div').attr('class');
$('input').attr('checked'); //checked
获取checked的时候,不管简写或者不简写都是checked,没有这个属性就是undefined,这个方法其实不太理想,最好是返回true/false,所以有了prop方法
赋值
$('div').attr('class', 'test');
prop
取值和赋值操作和attr一样
$('div').prop('class');
$('input').prop('checked'); //true
总结:
- 自定义属性只能通过attr取值和赋值(data-field)
- 类似于checked、selected、disabled,用prop方法比较明显
表单元素值取值和赋值
val 单个表单控件值
$('input').eq(0).val("新属性值")
更改属性值之后控制台elem显示的value值没有更改,这只是jQuery没有处理这个部分,实际上打印值还是有更改的,对后续操作没有任何影响
传函数,使用场景不是很多
$('input').eq(0).val(function(idx, oldVal) {
return oldValue + '新属性值';
})
serialize 表单内所有控件的值
控件要写在表单里才可以获取
$('form').serialize();
返回值是字符串(query string)
"text1=abc&text2=ddd&text3=ejl"
想要返回分开的对象数组
$('form').serializeArray();
each 遍历
ul > li * 5
$("li").each(function(idx, elem) {
$(elem).text(idx + 1)
.addClass("test-" + idx);
})
elem是原生DOM对象,如果不用$包的话,可以使用原生JS方法
遍历,将test和addClass两个function合并在一起,提升效率
$("li").text(function() {...})
$("li").addClass(function() {...})
index
$("ul").on("click", "li", function(e) {
console.log($(e.target).index());
})
$("li").on("click", function(e) {
console.log($("li").index($(e.target)));
})
两种写法都可以
DOM增删改查
查
next/prev 上一个/下一个元素
方法内可以传递参数,指定筛选条件
$("button").click(function() {
$(this).prev("span").css("fontSize", "30px");
})
前一个元素必须是span才可以生效
执行完prev会返回一个新的jQuery对象
nextAll
选择之后所有的元素
应用场景:选择都喜欢之后全部勾选
$("input").eq(0).click(function() {
if($("input").eq(0).prop("checked")) {
$(this).nextAll().prop("checked", true);
} else {
$(this).nextAll().prop("checked", false);
}
})
同样可以限制条件
$(this).nextAll("input[type='checkbox']")
nextUntil
<div id="logo">
<ul id="list">
<li class="item">1</li>
<li class="item">2</li>
<li class="item">3</li>
</ul>
</div>
<div>
<h1>篮球明星</h1>
都喜欢<input type="checkbox" />
库里<input type="checkbox" />
詹姆斯<input type="checkbox" />
哈登<input type="checkbox" />
<h1>足球明星</h1>
都喜欢<input type="checkbox" />
C罗<input type="checkbox" />
梅西<input type="checkbox" />
内马尔<input type="checkbox" />
</div>
如果用nextAll勾选都喜欢的话,所有的选框都会被勾选,要想区分两个部分的选框,就需要nextUntil
$("h1").next().click(function() {
if($(this).prop("checked")) {
$(this).nextUntil("h1").prop("checked", true);
} else {
$(this).nextUntil("h1").prop("checked", false);
}
})
siblings 兄弟元素
同级元素,同样可以传入参数筛选
parent 上一级父元素
parents 所有的父级元素 []
children 所有子元素
传入参数(选择器)可以指定需要哪个父级元素
closest 最近的元素,可以选自己
offsetParent 最近的祖先的定位元素
slice(start,end)选择一定范围的元素,左闭右开
增、改
$() 选择、创建元素
$("<div style='color: red'>test</div>").appendTo($("body"))
insertBefore/before;insertAfter/after
$(".box-3").insertBefore(".box-1");
两个掉个顺序,就是另外一个方法(等效)
$(".box-1").before($(".box-3"));
会有两个方法的原因就是链式调用,两个方法在前面的主体不一样
before如果传入的不是jQuery对象,就是一个文本插到前面,insertBefore不用传jQuery对象,只要传选择器就好
appendTo/prependTo 子元素添加到父元素里
append/prepend 父添加子
append是追加,prepend是加到最前面
wrap 被包裹
$("h1").wrap("<div class='container></div>")
$("h1").wrap($("<div class='container></div>"))
$("h1").wrap($(".container")); //复制
将h1通过wrap里的内容(div)包裹起来
这三种方法都可以,但是最后一种方法有个缺陷就是,"container"选择的元素是会复制过来的,而不是剪切,也就是说原来的"container"元素还在
函数
$("h1").wrap(function(idx) {
return "<div class='container-" + idx + "'></div>"
})
wrapInner 内部添加一层
<div class="container">
<h1>text</h1>
<h1>text</h1>
</div>
$(".container").wrapInner("<div></div>")
结果
<div class="container">
<div>
<h1>text</h1>
<h1>text</h1>
</div>
</div>
传函数也可
wrapAll 包裹有统一类名的元素到
<div class="container">
<h1>text</h1>
<h1>text</h1>
</div>
<div class="container">
<h1>text</h1>
<h1>text</h1>
</div>
$(".container").wrapAll("<div class='wrap'></div>")
result:
<div class='wrap'>
<div class="container">
<h1>text</h1>
<h1>text</h1>
</div>
<div class="container">
<h1>text</h1>
<h1>text</h1>
</div>
</div>
unwrap 去掉外层
<div class='wrap'>
<div class="container">
<h1>text</h1>
<h1>text</h1>
</div>
</div>
$("h1").unwrap()
result:
<div class='wrap'>
<h1>text</h1>
<h1>text</h1>
</div>
可以连续调用,一直去外层,到wrap为止
clone
默认不克隆事件,要克隆事件就传参true
自定义属性克隆不过去,用data
例:模板复制
<table>
<tr>
<th>姓名</th>
<th>年龄</th>
<th>职业</th>
</tr>
<tr class="tpl">
<td></td>
<td></td>
<td></td>
</tr>
</table>
样式为display: none
数据:
var tplArr = [
{
name: 'jackson',
age: 25,
job: 'singer'
},
{
name: 'ben',
age: 32,
job: 'teacher'
}
];
var tplTable = $("table");
tplArr.forEach(function(elem, idx) {
var cloneDOM = $(".tpl").clone().removeClass("tpl");
cloneDOM.find("td").eq(0).text(elem.name)
.next().text(elem.age)
.next().text(elem.job);
tplTable.append(cloneDOM);
})
data
设置自定义属性
$("div").data("data-set", "test");
还可以传入json
$("div").data({
name: "jsckson",
age: 25
});
取值
$("div").data("name");
在控制台elements上是看不到效果的,只能访问
例:
<div class="container">
<div class="tpl">
<p></p>
<p></p>
<button>添加</button>
</div>
<div class="resArea">
总价:<span class="total"></span>
</div>
</div>
var tplArr = [
{
id: "001",
name: 'jackson',
shoe: '阿迪达斯',
price: 2153
},
{
id: "001",
name: 'ben',
shoe: '耐克',
price: 1212
}
];
//模板
tplArr.forEach(function(elem, idx) {
var cloneDOM = $(".tpl").clone().removeClass("tpl");
cloneDOM.data({ //映射数据
id: elem.id,
name: elem.name,
shoe: elem.shoe,
price: elem.price
})
.find("p").eq(0).text(elem.shoe)
.next().text(elem.price);
cloneDOM.insertBefore($(".resArea"));
})
$("button").click(function() {
//隐式类型转化
$(".total").text(+$(".total").text() + $(this).parent().data("price"));
})
删
remove 事件无法恢复
$("div").click(function() {
alert("被点击啦~");
})
$("div").remove().appendTo("body")
remove之后绑定的事件也跟着移除了,再添加回去事件也不在了
detach 事件可以恢复
移除再添加事件还是在
事件
绑定on,解绑off
function handleClick() {
console.log("click");
}
$("div").on("click", handleClick);
$("div").off("click", handleClick);
$("div").off("click");
$("div").off(); //全部解绑
$("div").on("click", function() {
alert("被点击了一次");
})
$("div").on("click", function() {
alert("被点击了两次");
})
如果元素被绑定了多个相同的监听事件,都是会被执行的
还可以传入数据,通过e.data拿到
$("div").on("click", {test: "test"}, function(e) {
console.log(e.data)
})
事件委托
委托的元素写前面,触发的元素写后面
$("ul").on("click", "li", function(e, idx) {
console.log($(this).test());
//拿索引
var item = $(this),
list = document.getElementsByTagName("ul")[0],
idx = item.index(list);
})
还可以给特殊项进行绑定
$("ul").on("click", "li:even", handleClick);
$("ul").off("click", "li:even", handleClick);
可以绑定多个事件
$("div").on({
mouseenter: function() {
console.log("mouseenter");
},
click: function() {
console.log("click")
},
mouseleave: function() {
console.log(mouseleave);
}
})
trigger
function handleClick() {
console.log("click");
}
$("div").on("click", handleClick);
$("div").trigger("click")
触发事件,不是用户点击触发
应用场景:广告自动关闭
如果要让事件触发的时候传递一些额外的参数,触发的时候传递
function handleClick(e, a, b) {
console.log("click", a, b);
}
$("div").on("click", handleClick);
$("div").trigger("click", ["信息1","信息2"])
trigger还有一个重要的应用场景,就是触发自定义事件
$("div").on("customEvent", function() {
console.log("这个是自定义事件")
});
$("div").trigger("customEvent")
除了trigger找不到其他方法触发自定义事件了
one
one() 方法为被选元素添加一个或多个事件处理程序,并规定当事件发生时运行的函数。
当使用 one() 方法时,每个元素只能运行一次事件处理程序函数。
<a href="https://www.baidu.com"></a>
$("a").one("click", function() {
window.open("https://www.taobao.com");
return false; //阻止默认事件和冒泡
})
hover
鼠标移进和移出,可以合并成一个事件
$("div")
.on("mouseenter", function() {
console.log("mouse enter");
})
.on("mouseleave", function() {
console.log("mouse leave");
})
$("div").hover(function() {
console.log("mouse enter");
}, function() {
console.log("mouse leave");
})
keydown/keyup
$("input").keydown(function() {
$("input").css("backgroundColor", "green");
});
$("input").keyup(function() {
$("input").css("backgroundColor", "blue");
});
动画
<div class="container">
<h1>标题</h1>
<ul>
<li>text</li>
<li>text</li>
<li>text</li>
</ul>
</div>
ul{
display: none;
}
hide/show/toggle
$("h1")
.on("mouseenter", function() {
$(this).next().show();
})
.on("mouseleave", function() {
$(this).next().hide(3000);
})
里面传参,就会有渐变的效果
设置数字,就是时间
插件 jQuery easing plugin cdn
<script src="https://cdn.bootcdn.net/ajax/libs/jquery-easing/1.4.1/jquery.easing.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery-easing/1.4.1/jquery.easing.min.js"></script>
toggle
$("h1").on("click", function() {
if ($(this).next().css("display") == "none") {
$(this).next().show();
}else{
$(this).next().hide();
}
})
集显示与隐藏于一身,类似开关的效果
$("h1").on("click", function() {
$(this).next().toggle();
})
fadeIn/fadeOut/fadeToggle/fadeTo 改变opacity
$("h1").on("click", function() {
if ($(this).next().css("display") == "none") {
$(this).next().fadeIn();
}else{
$(this).next().fadeOut();
}
})
$("h1").on("click", function() {
$(this).next().fadeToggle();
})
fadeTo参数:时间、截止透明度、速度、回调
$("h1").on("click", function() {
$(this).next().fadeTo(1000, 0.5, "swing", function() {
conso;e.log("finished")
});
})
slideDown/slideUp/slideToggle
改变的都是纵向的数值
animate(style, speed, easing, callback)
<div class="container"></div>
$(".container").animate({
width: "200px",
height: "200px"
}, 5000, "swing", function() {
console.logo("finished");
})
可以不指定具体数值,让它在原来的基础上增加一定值
$(".container").animate({
width: "+=50px",
height: "+=50px"
});
css设置宽高为100,那么150的时候就会停止
还可以在回调函数里进行下一次动画
$(".container").animate({
width: "+=100px",
height: "+=100px",
top: "100px",
left: "100px"
}, 1000, "swing", function() {
console.log("第一次动画结束");
$(this).animate({
width: "+=20px",
height: "+=20px"
top: "0px",
left: "200px"
}, 5000, "swing", function() {
console.log("第二次动画结束");
})
})
不支持颜色,可以变化的只有和数值有关的
动画原理:动画队列(queue)
queue() 方法显示或操作在匹配元素上执行的函数队列。
$(".container")
.queue("test", function() {
console.log(1)
})
.queue("test", function() {
console.log(2)
})
.queue("test", function() {
console.log(3)
})
console.log($(".container").queue("test")); //[ƒ, ƒ, ƒ]
$(".container").dequeue("test"); //1
调用 .dequeue(),下一个排队的函数才能执行。
控制台打印
$(".container").queue("test") //[ƒ, ƒ]
$(".container").dequeue("test"); //2
执行完移除
$(".container")
.queue("test", function(next) {
console.log(1)
next();
})
.queue("test", function(next) {
console.log(2)
next();
})
.queue("test", function() {
console.log(3)
})
$(".container").dequeue("test");
console.log($(".container").queue("test"));
next方法可以连续执行,不需要dequeue,但是第一次触发还是要执行dequeue的
1
2
3
[]
clearQueue 清理队列
console.log("清理前", $(".container").queue("test"));
$(".container").clearQueue("test");
console.log("清理后", $(".container").queue("test"));
清理前 (3)[ƒ, ƒ, ƒ]
清理后 []
用队列实现上面的动画,其实之前的动画大概就是这么实现的
$(".container")
.on("click", function() {
$(this).dequeue("test");
})
.queue("test", function(next) {
$(this).animate({
width: "+=100px",
height: "+=100px",
top: "100px",
left: "100px"
})
next();
})
.queue("test", function() {
$(this).animate({
width: "+=20px",
height: "+=20px"
top: "0px",
left: "200px"
})
})
暂停动画 stop
<button class="startBtn">开始</button>
<button class="pauseBtn">暂停</button>
<button class="endBtn">结束</button>
<div class="container"></div>
开始
$(".startBtn").on("click", function() {
$(".container")
.animate({
width: "+=100px",
height: "+=100px",
top: "100px",
left: "100px"
}, 2000)
.animate({
width: "+=20px",
height: "+=20px",
top: "50px",
left: "200px"
}, 5000);
})
暂停
$(".pauseBtn").on("click", function() {
$(".container").stop();
})
这里的代码测试发现,小球似乎并没有停,但是每次结束的width和height不一样
所以stop()只是结束当前动画,第一个animate停了,第二个animate还会继续
要想让小球完全停止,只要在stop里传递参数true就可以了
$(".container").stop(true);
这样就可以清空动画队列,变成空数组[],不会有一个个f了
并且这里,除了可以传一个true之外,还可以传两个true
第一个true代表是否清空队列
第二个true代表第一个原本动画结束的点(200,200,100,100),按按钮会立即跳到当前动画的结尾
$(".container").stop(true, true); //停住,瞬移
$(".container").stop(false, true); //继续下一个动画,瞬移
延迟 delay
在两个动画之间可以设置延迟,这样就会等一下再继续下一个动画
$(".startBtn").on("click", function() {
$(".container")
.animate({
width: "+=100px",
height: "+=100px",
top: "100px",
left: "100px"
}, 2000)
.delay(3000)
.animate({
width: "+=20px",
height: "+=20px",
top: "50px",
left: "200px"
}, 5000);
})
jQuery.fx.off 移除过渡效果
jQuery.fx.off = true
没有动画效果,直接变换
尺度位置
offset 相对于文档的位置,和父元素无关
取值赋值皆可
("div").offset({"top": 50, "left": 50});
position 相对于父元素的位置
scrollLeft / scrollTop
窗口滚动条
$(window).scrollTop(); //取值
$(window).scrollTop(500); //赋值
元素内滚动
<div class="container">
<div class="item"></div>
</div>
.container {
width: 150px;
height: 150px;
padding: 20px;
margin: 20px;
border: 10px solid #424242;
overflow: auto;
}
.container .item{
width: 1500px;
height: 1500px;
background: orange;
}
$(".container").scrollTop(500);
width / innerWidth(+padding) / outerWidth(+padding + boeder)
$(".container").width(); //150
$(".container").innerWidth(); //190
$(".container").outerWidth(); //210
想要再加上margin值,往outerWidth里传true即可
$(".container").outerWidth(true); //250
工具方法
之前都是实例方法,直接$调用的是工具方法
$.type
对应的原生方法是typeof(),可以判断的类型有String、Number、Boolean、undefined、Object、Function,有缺陷,不利于判断Array、object、null
jQuery的$.type解决了这个问题
typeof([1, 2, 3]); //object
$.type([1, 2, 3]); //array
typeof(null); //object
$.type(null); //null
typeof(new Number()); //object
$.type(new Number()); //number
typeof(new Date()); //object
$.type(new Date()); //date
typeof(new RegExp()); //object
$.type(new RegExp()); //regexp
function Car(){};
typeof(new Date()); //object
$.type(new Date()); //object
.isFunction / $.isWindow...
$.trim 去掉头尾空格
和原生的trim结果一样
var str = " tes t ";
str.trim(); //tes t
$.trim(str); //tes t
$.proxy 改变this指向
类似于bind
参数:需要改变的方法,改变的this指向
function test() {
console.log(this);
}
var person = {
name: "jackson"
}
$.proxy(test, person);
test(); //window
proxy改变this指向并不是这么简单的,实际上proxy会返回一个新函数,在新函数里this指向才是指向Person的,旧函数this还是指向window
var testAfterProxy = $.proxy(test, person);
testAfterProxy(); {name: "jackson"}
所以需要一个变量接收返回的新函数
应用:
var test = {
init: function() {
this.elem = document.getElementsByClassName("test")[0];
this.num = 100;
this.bindEvent();
},
bindEvent: function() {
this.elem.addEventListener("click", $.proxy(this.showNum, this), false);
},
showNum: function() {
console.log(this.num);
}
}
test.init();
$.noConflict
jQuery担心其他库也使用$符号,所以设计了这个方法
var $NC = $.noConflict();
符号,原来的$符号就不能用了
$.each()
之前的实例方法是$().each
var arr = [1, 2, 3];
$.each(arr, function(idx, elem) {
console.log(idx, elem);
})
和forEach使用方法一样,甚至$.each()是forEach的前身,比forEach更早,性能来说还是forEach更好,所以一般还是用原生forEach
$.map
和$.each()情况一样,还是用原生比较好
var arr = [1, 2, 3];
var newArr = $.map(arr, function(idx, elem) {
return elem * 3;
})
console.log(newArr); //[3, 6, 9]
$.parseJSON
var json = '{"name": "jackson"}';
var res = $.parseJSON(json);
和原生的JSON.parse使用方法一样
JSON.stringify在jQuery里没有相对应的方法
$.makeArray
传一个参数的话,可以将类数组转变为数组
var obj = {
0: "jackson",
1: "eden",
2: "dnaiel",
length: 3
}
console.log($.makeArray(obj)); //["jackson", "eden", "dnaiel"]
传多个参数:
- 第二个参数传类数组,就会往类数组里追加对应的项
第一个参数传字符串、数组、布尔值等,都会追加
console.log($.makeArray("ben", obj)); // {0: "jackson", 1: "eden", 2: "dnaiel", 3: "ben", length: 4}
console.log($.makeArray(999, obj)); //{0: "jackson", 1: "eden", 2: "dnaiel", 3: 999, length: 4}
传数组,就会把数组里的内容依次追加到类数组里
var arr = [1, 2, 3];
console.log($.makeArray(arr, obj)); //{0: "jackson", 1: "eden", 2: "dnaiel", 3: 1, 4: 2, 5: 3, length: 6}
- 第二个参数传数组,数组追加
console.log($.makeArray(obj, arr)); // [1, 2, 3, "jackson", "eden", "dnaiel"]
总结:返回什么数据类型,看第二个参数
$.extend 扩展,自定义方法
方法内传递对象,设置属性方法
扩展工具方法
$.extend({
min: function(a, b) {
return a < b ? a : b;
}
});
console.logo($.min(15, 10));
扩展实例方法
$.fn就相当于jQuery.prototype
$.fn.extend({
clickToShowNumber: function() {
$(this).click(function() {
alert(($(this).text()) * 2);
})
}
});
$("ul li").clickToShowNumber();
浅拷贝,两种扩展都可以
var person1 = {
name: 'jaskson',
age: 25,
sex: 'male'
}
var person2 = {
name: 'eden',
age: 8,
job: 'student',
bro: {
name: 'ben'
}
}
$.extend(person1, person2);
console.log(person1, person2)
extend方法会将person2的值拷贝到person1中,如果有重复就替代掉,要注意的是浅拷贝,引用值指向的是同一个,一个更改了另一个也会更改
如果有三个参数,person2拷贝到person1,得出结果,再被person3覆盖,以此类推
深拷贝,第一个参数传true即可
$.extend(true, person1, person2);
引用值也会拷贝覆盖,但不是浅拷贝的那种覆盖了,而是在person1中创建一个同名对象,然后逐步添加键值对
$.ajax
jsonpPlaceholder API: jsonplaceholder.typicode.com/
$.ajax({
url: 'http://jsonplaceholder.typicode.com/users',
type: 'GET',
dataType: 'JSON', //期待服务器返回的数据类型
timeout: 1000,
async: true, //是否异步,默认就是true
success: function(res) {
console.log(res);
},
error: function(e) {
console.log(e);
},
complete: function() {
// 无论成功还是失败都会执行这个方法
},
context: document.body //改变this指向
})
源码
;(function() {
function jQuery(selector) {
//通过这个函数调用,传入参数,执行init函数,由于init是构造函数,再new实例化一下
return new jQuery.prototype.init(selector);
}
jQuery.prototype.init = function(selector) {
// this = {}; init函数实例化出来this
// 按照相应的选择器,找到对应的DOM元素,包装成jQuery对象并返回
this.length = 0;
if (selector == null) {
return this;
}
if (typeof selector == 'string' && selector.indexOf('.') != -1) {
var elem = document.getElementsByClassName(selector.slice(1));//slice去点
} else if(typeof selector == 'string' && selector.indexOf('#') != -1) {
var elem = document.getElementById(selector.slice(1));
}
if (selector instanceof Element || elem.length == undefined) {
this[0] = elem || selector;
this.length ++;
} else {
for (var i = 0; i < elem.length; i++) {
this[i] = elem[i];
this.length ++;
}
}
}
// css方法不在jQuery.prototype.init里面,无法调用
jQuery.prototype.init.prototype = jQuery.prototype;
jQuery.prototype.css = function(option) {
for (var i = 0; i < this.length; i++) {
// this就是init实例化出来的this,里面包含选出来的元素
for(var attr in option) {
this[i].style[attr] = option[attr];
}
}
return this; //实现链式调用
}
jQuery.prototype.get = function(number) {
if (number == null) {
// 空截,不截取,将类数组变成数组
return [].slice.call(this, 0)
} else {
if (number >= 0) {
return this[number];
} else {
// 负数就数字+长度
return this[number + this.length];
}
}
}
jQuery.prototype.eq = function(number) {
// 返回jQuery对象
var elem = number != null
? (number >= 0 ? this[number] : this[number + this.length])
: [].slice.call(this, 0);
// return jQuery(elem); //数组变成类数组
// 上一步放到pushStack里实现
return this.pushStack(elem);
}
jQuery.prototype.add = function(selector) {
var curObj = jQuery(selector),
baseObj = this,
newObj = jQuery(); //空对象
for (var i = 0; i < curObj.length; i++) {
newObj[newObj.length++] = curObj[i];
}
for (var i = 0; i < curObj.length; i++) {
newObj[newObj.length++] = baseObj[i];
}
this.pushStack(newObj);
return newObj;
}
jQuery.prototype.end = function() {
return this.prevObject;
}
jQuery.prototype.pushStack = function(elem) {
if (elem.constructor != jQuery) {
elem = jQuery(elem);
}
elem.prevObject = this;
return elem;
}
window.$ = window.jQuery = jQuery;
})();