JavaScript世界中使用最广泛的一个库,jQuery的理念“Write Less, Do More“,让你写更少的代码,完成更多的工作。jQuery能帮我们干这些事情:
- 消除浏览器差异:你不需要自己写冗长的代码来针对不同的浏览器来绑定事件,编写AJAX等代码;
- 简洁的操作DOM的方法:写
$('#test')肯定比document.getElementById('test')来得简洁; - 轻松实现动画、修改CSS等各种操作。
// 使用<html><head> <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> ...</head><body> ...</body></html>$是著名的jQuery符号。实际上,jQuery把所有功能全部封装在一个全局变量jQuery中,而$也是一个合法的变量名,它是变量jQuery的别名:
window.jQuery; // jQuery(selector, context)window.$; // jQuery(selector, context)$ === jQuery; // truetypeof($); // 'function'$本质上就是一个函数,但是函数也是对象,于是$除了可以直接调用外,也可以有很多其他属性。注意,你看到的$函数名可能不是jQuery(selector, context),因为很多JavaScript压缩工具可以对函数名和参数改名,所以压缩过的jQuery源码$函数可能变成a(b,c)。绝大多数时候,我们都直接用$(因为写起来更简单嘛)。但是,如果$这个变量不幸地被占用了,而且还不能改,那我们就只能让jQuery把$变量交出来,然后就只能使用jQuery这个变量:
// 原理是jQuery在占用$之前,先在内部保存了原来的$,调用jQuery.noConflict()时会把原来保存的变量还原。$; // jQuery(selector, context)jQuery.noConflict();$; // undefinedjQuery; // jQuery(selector, context)选择器
跳转到“选择器”选择器是jQuery的核心。一个选择器写出来类似$('#dom-id')。
为什么jQuery要发明选择器?jQuery的选择器就是帮助我们快速定位到一个或多个DOM节点。回顾一下DOM操作中我们经常使用的代码:
// 按ID查找:let a = document.getElementById('dom-id');
// 按tag查找:let divs = document.getElementsByTagName('div');
// 查找<p class="red">:let ps = document.getElementsByTagName('p');// 过滤出class="red":// TODO:
// 查找<table class="green">里面的所有<tr>:let table = ...for (let i=0; i<table.children; i++) { // TODO: 过滤出<tr>}这些代码实在太繁琐了,并且,在层级关系中,例如,查找<table class="green">里面的所有<tr>,一层循环实际上是错的,因为<table>的标准写法是:
<table> <tbody> <tr>...</tr> <tr>...</tr> </tbody></table>什么是jQuery对象?jQuery对象类似数组,它的每个元素都是一个引用了DOM节点的对象。
// 按ID查找// 查找<div id="abc"> ,#abc以#开头。返回的对象是jQuery对象。let div = $('#abc');// 返回[<div id="abc">...</div>]// 如果id为abc的<div>不存在,返回的jQuery对象如下:[]
// jQuery对象和DOM对象之间可以互相转化:let div = $('#abc'); // jQuery对象let divDom = div.get(0); // 假设存在div,获取第1个DOM元素let another = $(divDom); // 重新把DOM包装为jQuery对象| 查找方式 | 选择器语法 | 详细说明 | 代码示例 |
|---|---|---|---|
| 按ID查找 | #id | 通过元素的 id 属性查找,使用 # 号开头。返回的 jQuery 对象类似数组。 | let div = $('#abc'); |
| 按Tag查找 | tag | 通过元素的 tag 名称查找。可以获取页面中所有指定的标签元素。 | let ps = $('p'); |
| 按Class查找 | .class | 通过元素的 class 属性查找,使用 . 号开头。可以查找包含特定 class 的所有元素。 | let a = $('.red'); |
| 按属性查找 | [attribute=value] | 按照指定属性及其值查找元素。适用于查找特定属性的元素。 | let email = $('[name=email]'); |
| 按属性前缀查找 | [attribute^=prefix] | 查找指定属性的值以给定前缀开头的元素。 | let icons = $('[name^=icon]'); |
| 按属性后缀查找 | [attribute$=suffix] | 查找指定属性的值以给定后缀结尾的元素。 | let names = $('[name$=with]'); |
| 组合查找 | tag.class, tag[attribute] | 结合 tag、class 或 attribute 等多种选择器组合进行查找。 | let emailInput = $('input[name=email]'); |
| 多项选择器 | selector1, selector2, ... | 多个选择器通过 , 号分隔来组合查找。返回的元素是按照它们在 HTML 中出现的顺序排列的。 | $('p.red,p.green'); |
// 按ID查找let div = $('#abc');
// 按Tag查找let ps = $('p');
// 按Class查找let a = $('.red');
// 按属性查找let email = $('[name=email]');
// 按属性前缀查找let icons = $('[name^=icon]');
// 按属性后缀查找let names = $('[name$=with]');
// 组合查找let emailInput = $('input[name=email]');
// 多项选择器$('p.red,p.green');| 选择器类型 | 说明 | jQuery代码示例 |
|---|---|---|
| 层级选择器 | 根据层级关系选择元素,使用空格分隔。 | $('ancestor descendant'); |
选择
| $('ul.lang li'); | |
| 选择 元素下的所有 | $('div.testing li'); | |
| 子选择器 | 选择直接子元素,使用>分隔。 | $('parent>child'); |
选择
| $('ul.lang>li'); | |
| 过滤器 | 附加在选择器上,帮助更精确地定位元素。 | $('ul.lang li:first-child'); |
| 选择第一个 | $('ul.lang li:first-child'); | |
| 表单相关选择器 | 选择特定类型的表单元素。 | :input, :file, :checkbox, :radio, :focus, :checked, :enabled, :disabled |
| 可见/隐藏选择器 | 选择可见或隐藏的元素。 | $('div:visible');, $('div:hidden'); |
| 查找 | 在jQuery对象的子节点中查找,使用find()方法。 | ul.find('.dy'); |
| 上查找 | 从当前节点向上查找,使用parent()方法。 | $('#swift').parent(); |
| 相邻节点查找 | 查找相邻的同级节点,使用next()和prev()方法。 | $('#swift').next();, $('#swift').prev('.dy'); |
| 过滤 | 过滤掉不符合条件节点,使用filter()方法。 | langs.filter('.dy'); |
| 函数过滤 | 传入函数进行过滤,this绑定为DOM对象。 | langs.filter(function () { return this.innerHTML.indexOf('S') === 0; }); |
| 映射 | 将jQuery对象的DOM节点转化为其他对象,使用map()方法。 | langs.map(function () { return this.innerHTML; }).get(); |
| 首/尾节点选择 | 返回jQuery对象的第一个或最后一个节点,使用first()和last()方法。 | langs.first();, langs.last(); |
| 切片选择 | 返回jQuery对象的子集,使用slice()方法。 | langs.slice(2, 4); |
操作DOM
跳转到“操作DOM”<!-- HTML结构 --><ul id="test-ul"> <li class="js">JavaScript</li> <li name="book">Java & JavaScript</li></ul>
$('#test-ul li[name=book]').text(); // 'Java & JavaScript'$('#test-ul li[name=book]').html(); // 'Java & JavaScript'
// jQuery的API设计非常巧妙:无参数调用text()是获取文本,传入参数就变成设置文本,HTML也是类似操作let j1 = $('#test-ul li.js');let j2 = $('#test-ul li[name=book]');
j1.html('<span style="color: #c00">JavaScript</span>');j2.text('JavaScript & ECMAScript');
$('#test-ul li').text('JS'); // 是不是两个节点都变成了JS?// 如果不存在id为not-exist的节点:$('#not-exist').text('Hello'); // 代码不报错,没有节点被设置为'Hello'修改css
<!-- HTML结构 --><ul id="test-css"> <li class="lang dy"><span>JavaScript</span></li> <li class="lang"><span>Java</span></li> <li class="lang dy"><span>Python</span></li> <li class="lang"><span>Swift</span></li> <li class="lang dy"><span>Scheme</span></li></ul>
$('#test-css li.dy>span').css('background-color', '#ff0').css('color', '#c00');
// 注意,jQuery对象的所有方法都返回一个jQuery对象(可能是新的也可能是自身),这样我们可以进行链式调用,非常方便。let div = $('#test-div');div.css('color'); // '#000033', 获取CSS属性div.css('color', '#336699'); // 设置CSS属性div.css('color', ''); // 清除CSS属性
// css()方法将作用于DOM节点的style属性,具有最高优先级。如果要修改class属性,可以用jQuery提供的下列方法let div = $('#test-div');div.hasClass('highlight'); // false, class是否包含highlightdiv.addClass('highlight'); // 添加highlight这个classdiv.removeClass('highlight'); // 删除highlight这个class修改DOM结构
<div id="test-div"> <ul> <li><span>JavaScript</span></li> <li><span>Python</span></li> <li><span>Swift</span></li> </ul></div>
let ul = $('#test-div>ul');ul.append('<li><span>Haskell</span></li>'); //调用append()传入HTML片段
// append()还可以传入原始的DOM对象,jQuery对象和函数对象// 创建DOM对象:let ps = document.createElement('li');ps.innerHTML = '<span>Pascal</span>';// 添加DOM对象:ul.append(ps);
// 添加jQuery对象:ul.append($('#scheme'));
// 添加函数对象:ul.append(function (index, html) { return '<li><span>Language - ' + index + '</span></li>';});
// 如果要把新节点插入到指定位置,可以先定位到JavaScript,然后用after()方法:let js = $('#test-div>ul>li:first-child');js.after('<li><span>Lua</span></li>');
// 要删除DOM节点,拿到jQuery对象后直接调用remove()方法就可以了。如果jQuery对象包含若干DOM节点,实际上可以一次删除多个DOM节点let li = $('#test-div>ul>li');li.remove(); // 所有<li>全被删除事件
跳转到“事件”因为JavaScript在浏览器中以单线程模式运行,页面加载后,一旦页面上所有的JavaScript代码被执行完后,就只能依赖触发事件来执行JavaScript代码。浏览器在接收到用户的鼠标或键盘输入后,会自动在对应的DOM节点上触发相应的事件。如果该节点已经绑定了对应的JavaScript处理函数,该函数就会自动调用。由于不同的浏览器绑定事件的代码都不太一样,所以用jQuery来写代码,就屏蔽了不同浏览器的差异,我们总是编写相同的代码。
/* HTML: * * <a id="test-link" href="#0">点我试试</a> * */// 获取超链接的jQuery对象:let a = $('#test-link');a.on('click', function () { // on方法用来绑定一个事件,我们需要传入事件名称和对应的处理函数。 alert('Hello!');});
// 更简化的写法是直接调用click()方法:a.click(function () { alert('Hello!');});
// 有些事件,如mousemove和keypress,我们需要获取鼠标位置和按键的值,否则监听这些事件就没什么意义了。所有事件都会传入Event对象作为参数,可以从Event对象上获取到更多的信息$(function () { $('#testMouseMoveDiv').mousemove(function (e) { $('#testMouseMoveSpan').text('pageX = ' + e.pageX + ', pageY = ' + e.pageY); });});
// 一个已被绑定的事件可以解除绑定,通过off('click', function)实现:unction hello() { alert('hello!');}
a.click(hello); // 绑定事件
// 10秒钟后解除绑定:setTimeout(function () { a.off('click', hello);}, 10000);
// 一个需要注意的问题是,事件的触发总是由用户操作引发的。例如,我们监控文本框的内容改动:let input = $('#test-input');input.change(function () { console.log('changed...');});// 当用户在文本框中输入时,就会触发change事件。但是,如果用JavaScript代码去改动文本框的值,将不会触发change事件:let input = $('#test-input');input.val('change it!'); // 无法触发change事件// 有些时候,我们希望用代码触发change事件,可以直接调用无参数的change()方法来触发该事件:let input = $('#test-input');input.val('change it!');input.change(); // 触发change事件| 事件类型 | 说明 | jQuery代码示例 |
|---|---|---|
| click | 鼠标单击时触发。 | $('#myButton').click(function() { alert('Clicked!'); }); |
| dblclick | 鼠标双击时触发。 | $('#myElement').dblclick(function() { alert('Double clicked!'); }); |
| mouseenter | 鼠标进入元素时触发。 | $('#myElement').mouseenter(function() { alert('Mouse entered!'); }); |
| mouseleave | 鼠标离开元素时触发。 | $('#myElement').mouseleave(function() { alert('Mouse left!'); }); |
| mousemove | 鼠标在元素内部移动时触发。 | $('#myElement').mousemove(function() { alert('Mouse moving!'); }); |
| hover | 鼠标进入和退出元素时分别触发两个函数。 | $('#myElement').hover( function() { alert('Mouse entered!'); }, function() { alert('Mouse left!'); } ); |
| keydown | 键盘按键被按下时触发(作用于获得焦点的DOM)。 | $('#myInput').keydown(function() { alert('Key down!'); }); |
| keyup | 键盘按键被松开时触发(作用于获得焦点的DOM)。 | $('#myInput').keyup(function() { alert('Key up!'); }); |
| keypress | 每次按键时触发(作用于获得焦点的DOM)。 | $('#myInput').keypress(function() { alert('Key pressed!'); }); |
| focus | 元素获得焦点时触发。 | $('#myInput').focus(function() { alert('Element focused!'); }); |
| blur | 元素失去焦点时触发。 | $('#myInput').blur(function() { alert('Element blurred!'); }); |
| change | 输入字段、选择框或文本域的值改变时触发。 | $('#myInput').change(function() { alert('Value changed!'); }); |
| submit | 表单提交时触发。 | $('#myForm').submit(function() { alert('Form submitted!'); }); |
| ready | 页面DOM树完成初始化后触发,适合写初始化代码。 | $(document).ready(function() { alert('DOM ready!'); }); |
| 事件类型 | 说明 | jQuery代码示例 |
|---|---|---|
| 鼠标事件 | 包括点击、双击、鼠标移动等事件。 | $('#test-link').on('click', function () { alert('Hello!'); }); |
| 键盘事件 | 作用在获得焦点的DOM上,如<input>和<textarea>。 | $('#test-input').on('keydown', function () { console.log('Key down'); }); |
| 其他事件 | 如焦点、内容改变、表单提交等。 | $('#testForm').on('submit', function () { alert('Form submitted!'); }); |
| ready事件 | 当页面DOM树完成初始化后触发,适合写初始化代码。 | $(document).ready(function () { // Initialization code }); |
| 事件参数 | 事件处理函数可以访问Event对象,获取更多事件信息。 | $('#testMouseMoveDiv').on('mousemove', function (e) { console.log(e.pageX, e.pageY); }); |
| 取消绑定 | 移除已绑定的事件处理函数。 | $('#test-link').off('click', function () { alert('Hello!'); }); |
| 事件触发条件 | 事件通常由用户操作触发,但也可以手动触发。 | $('#test-input').val('change it!').trigger('change'); |
动画
跳转到“动画”用JavaScript实现动画,原理非常简单:我们只需要以固定的时间间隔(例如,0.1秒),每次把DOM元素的CSS样式修改一点(例如,高宽各增加10%),看起来就像动画了。但是要用JavaScript手动实现动画效果,需要编写非常复杂的代码。如果想要把动画效果用函数封装起来便于复用,那考虑的事情就更多了。使用jQuery实现动画,代码已经简单得不能再简化了:只需要一行代码!
| 动画类型 | 说明 | jQuery代码示例 |
|---|---|---|
| show / hide | 显示或隐藏元素,可以带时间参数实现动画效果。 | $('#test-show-hide').show('slow'); |
| toggle | 根据当前状态决定是显示还是隐藏,也可以带时间参数。 | $('#test-toggle').toggle('slow'); |
| slideUp / slideDown | 垂直方向展开或收起元素,可以带时间参数实现动画效果。 | $('#test-slide').slideUp('slow'); |
| slideToggle | 根据元素是否可见来决定slideUp或slideDown。 | $('#test-slide-toggle').slideToggle('slow'); |
| fadeIn / fadeOut | 淡入淡出效果,通过设置opacity属性实现。 | $('#test-fade').fadeIn('slow'); |
| fadeToggle | 根据元素是否可见来决定fadeIn或fadeOut。 | $('#test-fade-toggle').fadeToggle('slow'); |
| animate | 自定义动画效果,通过改变CSS属性实现。 | $('#test-animate').animate({opacity: 0.25, width: '256px', height: '256px'}, 3000); |
| 串行动画 | 通过delay实现动画效果的串行执行和暂停。 | $('#test-animates').slideDown(2000).delay(1000).animate({width: '256px', height: '256px'}, 2000); |