PS:关于JS的学习,暂时就告一段落了。临近新年,杂事很多。
JQuery:
之前只知道JQuery是JavaScript框架,就是简化了操作DOM。理解得比较片面。事实上使用JQuery除了简单还有其他的好处:
- 消除浏览器差异:你不需要自己写冗长的代码来针对不同的浏览器来绑定事件,编写AJAX等代码;
- 轻松实现动画、修改CSS等各种操作。
既然如此,那么JavaScript能做的,JQuery应该都要封装好。
引用:
<!-- 跨域引用js -->
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<!-- 引用本地js -->
<script src="jquery-3.3.1.js"></script>
选择器:
要操作DOM就要先获取到DOM对象的引用。JS代码的方式就是使用var p = document.getElementById('id')这种。JQuery就很简单了:
var p = $('#idval');
看上去非常神奇,之前一直没有考虑过$是什么东西,事实上,$就是一个变量名而已。
typeof($) //"function"
jQuery === $ //true
window.jQuery === jQuery //true
JQuery提供了一个全局的对象,jQuery,所有的操作都封装在里面,然后为了更简单,用$指向这个jQuery,$是一个合法的变量嘛。所以最后看起来,就非常简单。
那么,如果window.$被占用了 怎么让jQuery不影响到window.$呢?如下:
var new$ = jQuery.noConflict(); //用new$ 代替jQuery 当然 直接用jQuery也可以
//此时 $原来是什么 就是什么 不会收到影响
来看JQuery的源码是如何实现noConflict的:其实很简单,就是先把原始值保存下来,如果用户有需求,恢复原始值就可以了。
var
// Map over jQuery in case of overwrite
_jQuery = window.jQuery,
// Map over the $ in case of overwrite
_$ = window.$; //保存window.$的原始值
jQuery.noConflict = function( deep ) { //恢复$或jQuery的原始值
if ( window.$ === jQuery ) { //jQuery是JQuery文件定义的,默认让window.$指向它
window.$ = _$; //把window.$恢复到之前保存的window.$原始值
}
if ( deep && window.jQuery === jQuery ) {
window.jQuery = _jQuery;
}
return jQuery;
};
接下来开始系统的看一下选择器都有哪些:
id,class,标签,属性:
//按id查找
$('#idname')
//按class查找
$('.classname')
//按标签TagName查找
$('p') //查找p标签
//按属性查找 id和calss也属于属性
$('[name=value]')
$('[name="value"]') //如果value有特殊值比如- & 需要加双引号
$('[name^=value]') //以value开头
$('[name$=value]') //以value结尾
多个class同时满足:与
//因为html标签的class属性值可能有很多个
$('.classname1.classname2') //同时包含两个执行的calss
多个选择器有一个满足:或
$('p,#idname') //选择p标签 或者id=idname的节点
组合选择:
//把上面的四个选择器组合在一起
$('p.classname[name=value]');
$('#idname[name=value]');
需要注意的是,使用选择器获取到的不是DOM对象,而是JQuery对象。
//一般来说,用JQuery的话 直接操作JQuery对象更方便,所以不需要做多余的什么
var pjq = $('#idname');
var pdom = pjq.get(0); //JQuery对象转DOM对象
$(pdom); //DOM对象转JQuery对象
层级选择器:
除了基本选择的方式 还可以根据DOM树的结构来做选择:
//选择 div 标签的子孙p 的子孙span
$('div p span'); //用空格
//选择div 标签的儿子p 的儿子span
$('div>p>span'); //用>
过滤器:
//写好一个选择器后 又可以依然不符合要求 这个时候就需要filter
$('#idname[name=value]:first'); //选第一个孩纸 用:first
//类似的还有:last :even :odd
表单:
:input
:可以选择<input>
,<textarea>
,<select>
和<button>
;:file
:可以选择<input type="file">
,和input[type=file]
一样;:checkbox
:可以选择复选框,和input[type=checkbox]
一样;:radio
:可以选择单选框,和input[type=radio]
一样;:focus
:可以选择当前输入焦点的元素,例如把光标放到一个<input>
上,用$('input:focus')
就可以选出;:checked
:选择当前勾上的单选框和复选框,用这个选择器可以立刻获得用户选择的项目,如$('input[type=radio]:checked')
;:enabled
:可以选择可以正常输入的<input>
、<select>
等,也就是没有灰掉的输入;:disabled
:和:enabled
正好相反,选择那些不能输入的。
以上基本用法知道了就差不多了。另外,JQuery的链式调用允许我们JQuery对象上查找。说得有得不清楚,看代码:
var dady = $('div.dady');
var son = dady.find('p[name=value]'); //直接在JQuery上调用find查找
dady.parent(); //返回dady的父亲节点
son.next(); //同级的下一个节点 可加选择器参数
son.prev(); //同级的上一个节点 可加选择器参数
dady.first(); //第一个孩子
dady.last(); //最后一个
dady.slice(2,4); //第2到3个孩子
dady.filter('[name=value]'); //过滤 只留下满足条件的 可传函数 return true保留
dady.map(function(){}); //就和数组那个map一样
有了各种各样的获取节点的方法,接下来就是操作这个节点了:
操作DOM:
参考之前JS的内容,需要修改节点内容,CSS,属性等。基本做法如下:
var p = $('#idname');
//修改节点内容
p.text(); //获取
p.text('内容'); //设置
p.html();
p.html('<span>内容</span>');
//修改css 作用于DOM节点的style属性
p.css('color', '#ff0000'); //js是使用style 并且属性名用驼峰式
//JQuery直接用css 和css的属性名,也可以用js的驼峰式
//修改class
p.hasClass('classname');
p.addClass('classname');
p.removeClass('classname') //不是删除class属性 是删除class中的属性
//操作属性
//获取
p.width(); // 600
p.height(); // 300
p.width(400); // 设置CSS属性 width: 400px,是否生效要看CSS是否有效
p.height('200px'); // 设置CSS属性 height: 200px,是否生效要看CSS是否有效
//修改
p.attr('name'); //获取name属性
p.attr('name', 'Hello'); //设置
p.removeAttr('name'); //删除name属性
//也可以用prop()它们只获取radio和select这种 checked selected属性是有差异
p.attr('checked'); //'checked';
p.prop('checked'); //true;
//不过一般也不这么用 一般使用is方法来判断是否被选中
p.is(':checked');
p.is(':selected');
//操作表单 jQuery对象统一提供val()方法获取和设置对应的value属性:
p.val(); //获取 包括select也是这样
p.val('value') //设置
查和改做完了之后,就是增加和删除节点:
var dady = $('div.dady');
//添加
dady.append('<p>内容</p>'); //直接添加HTML片段
dady.append('jQuery对象');
dady.append('DOM对象'');
dady.append(function(){
return 'HTML片段 || jQuery对象 || DOM对象';
});
//要添加到最前面使用prepend()
//同级的情况下 使用after()或者before()方法
//删除
dady.remove();
至此,JQuery是如何操作DOM的,就和JS可以一一对上了。
事件:
鼠标事件
- click: 鼠标单击时触发;
- dblclick:鼠标双击时触发;
- mouseenter:鼠标进入时触发;
- mouseleave:鼠标移出时触发;
- mousemove:鼠标在DOM内部移动时触发;
- hover:鼠标进入和退出时触发两个函数,相当于mouseenter加上mouseleave。
键盘事件
- 键盘事件仅作用在当前焦点的DOM上,通常是<input>和<textarea>。
- keydown:键盘按下时触发;
- keyup:键盘松开时触发;
- keypress:按一次键后触发。
其他事件
- focus:当DOM获得焦点时触发;
- blur:当DOM失去焦点时触发;
- change:当<input>、<select>或<textarea>的内容改变时触发;
- submit:当<form>提交时触发;
- ready:当页面被载入并且DOM树完成初始化后触发。
//绑定事件
p.on('click', function(){
console.log('触发了click事件');
});
//简写成
p.click(function(){
console.log('触发了click事件');
});
//解绑事件
p.off('click'); //解绑p上的click事件的所有函数,使用第二个只接触指定函数(需要有这个函数的引用)
p.off(); //解绑p上的所有事件
//ready事件
$(document).on('ready', function(){}); //作用于document
$(document).ready(function(){}); //简化
$(function(){}); //最简
需要注意:
- 触发事件之后,函数是会接收到一个事件的参数event的 事件的信息可以从这个参数中获取。
- 如果连续绑定多个函数,后面的函数不会覆盖前面的,当事件被触发时,多个函数按顺序执行。
- 模拟手动触发
input.change()
相当于input.trigger('change')
,它是trigger()
方法的简写。 -
// 无法弹出新窗口,将被浏览器屏蔽: 需要在用户触发的事件中去调用它 这是基于安全的考虑 $(function () { window.open('/'); });
关于事件还有一点需要注意:try catch finally
var p = $('#idname');
try{
p.click(function(){
throw new Error('故意抛出错误');
});
}catch(e){
console.log('出错了');
}finally{
}
上面这段异常处理代码咋一看没什么问题,但实际上 它会直接走try finally。因为绑定事件并不代表会执行里面的function()。只有用户触发的时候,才会抛出异常,但那个时候,这个异常处理块早就执行完了。
正确做法如下:
var p = $('#idname');
p.click(function(){
try{
throw new Error('故意抛出错误');
}catch(e){
console.log('出错了');
}finally{
}
});
动画:
用JS实现动画的原理很简单,每隔一个比较小的间隔比如20毫秒 改变一次DOM节点的属性。知道了这一点就够了。不过实现起来就很麻烦了。
隐藏和显示
var img = $('#img');
显示 隐藏
左上角收缩
img.hide('slow'); //可以用字符串 也可以用数字 不带参数就瞬间完成
img.show(1000);
img.toggle(1000);
//上下滑动 窗帘
img.slideDown(1000); //下滑显示
img.slideUp(1000); //上滑隐藏
img.slideToggle(1000);
//淡进淡出
img.fadeOut(1000);
img.fadeIn(1000);
img.fadeToggle(1000);
自定义动画
//自定义动画
img.animate({
opacity: 0.25,
width: '256px',
height: '256px'
}, 3000, function(){
console.log('动画已结束');
$(this).css('opacity', 1.0); //this是DOM对象
});
串行动画:链式调用
//多个动画按顺序执行
img.animate({
width: '200px',
height: '200px'
}, 2000)
.delay(1000) //延迟
.slideUp(1000)
.fadeIn(1000);
AJAX:
基本使用:
//ajax(url, setting) 返回一个jqXHR(XmlHttpRequest)对象
var jqxhr = $.ajax('url', {
async: true, //是否异步执行AJAX请求 默认true
Method: 'GET', //缺省为'GET'
contenType: 'application/json', //默认值为'application/x-www-form-urlencoded; charset=UTF-8',也可以指定为text/plain
data: '可以是字符串,数组或Object', //如果是GET请求,data将被转换成query附加到URL上,如果是POST请求,根据contentType把data序列化成合适的格式
headers: '必须是一个object', //额外的HTTP头
dataType: 'json' //接收的数据格式,可以指定为'html'、'xml'、'json'、'text'等,缺省情况下根据响应的Content-Type猜测
});
//jqXHR对象类似Promise对象 可以用链式调用处理请求结果
jqxhr.done(function(data){
ajaxLog('数据:'+JSON.stringify(data));
}).fail(function(xhr, status){
ajaLog('失败:'+xhr.status+",原因:"+status);
}).always(function(){
ajaLog('请求完成');
});
简写:
//get请求 第二个参数如果是object,jQuery自动把它变成query string然后加到URL后面 就是?后面的内容
$.get('url', {
name: 'lisi',
sex: 'male'
})
//post请求 第二个参数默认被序列化为application/x-www-form-urlencoded
//实际构造的数据作为POST的body被发送。
$.post('url', {
name: 'lisi',
sex: 'male'
})
//getJSON 接收类型为json
$.getJSON('url', {
name: 'lisi',
sex: 'male'
}).done(function(data){
//这里的data已经是JSON对象了
});
编写JQuery插件的原则:
- 给
$.fn
绑定函数,实现插件的代码逻辑; - 插件函数最后要
return this;
以支持链式调用; - 插件函数要有默认值,绑定在
$.fn.<pluginName>.defaults
上; - 用户在调用时可传入设定值以便覆盖默认值。