22、JQ的基础语法、核心原理和项目实战
jQ的版本和下载
jQuery版本
1.x:兼容IE6-8,是目前PC端开发常用的类库。
2.x/3.x:不支持IE6-8,应用比较少,移动端开发用zepto.js
jQery常用版本
jquery-1.9.3.js
jquery-1.11.3.js
jquery.min.js下载JQ
官网下载:http://jquery.com/
GitHub:https://github.com/jquery/jquery 下载JQ的源码进行学习和分析
看JQ的API手册:http://jquery.cuishifeng.cn/
锋利的JQ第二版:对于JQ的基础知识和实战应用讲解的非常好
在npm中查看所有jQuery的版本号的命令 :npm view jquery versions
npm install jquery 是安装最新版本
如果我想要引入的是Jquery的1.7.2版本,则输入npm intall [email protected]
JQuery的核心原理解读(分析源代码)
JQ是一个常用方法类库(常用dom库),提供了很多真实项目中需要使用的属性和方法(这些方法JQ已经帮我们完善了浏览器的兼容处理以及一些细节的优化)
jQuery本身是一个类
当我们在JS中执行
- $(selector,context)
- jQery(selector,context)
都是在创建一个JQ类的实例($===jQuery),这些实例都是一个类数组(我们把这个类数组称为jQuery对象),jQ的实例可以使用jQ原型上提供的公有的属性和方法;
var jQuery=function(selector,context){
return new jQuery.fn.init(selector, context);
};
//重构原型
jQuery.fn=jQuery.prototype={
jquery:version,
constructor:jQuery,
...
};
...
init=jQuery.fn.init=function(selector, context){
if(typeof selector=="string"){
...
}else if(selector.nodeType){
...
}else if(jQuery.isFunction(selector)){
...
}
return jQuery.makeArray(selector,this );//=>返回的是一个类数组
}
init.prototype=jQuery.fn;
...
window.jQuery=window.$=jQuery;
项目中我们把"$()"称之为jQ的选择器,因为执行这个方法可以传递两个参数进去,通过selector我们可以获取到需要操作的DOM元素集合(jQ类数组集合),通过context可以获取到当前元素的上下文(不传递默认是document,如果传递,我们传递一个JS元素对象即可);
- selector支持三种格式:
传递的如果是个字符串,能够通过选择器获取到元素
传递的是个元素对象,它的意思是把JS原生对象转换为JQ对象
传递的是个函数,它代表等DOM结构加载完成再执行函数中对应的JS代码(类似于window.onload)
我们用jQuery获取的值一般都使用$开头的变量名来存储(以后看见变量名是以$开头的,我们就知道是JQ获取的实例,即JQ对象
$()、jQuery()对象获取的是一个类数组
第一个参数传递的如果是一个字符串,就是通过选择器获取到需要的元素集合(获取的都是类数组集合:如果没有获取到,结果就是一个空的集合,而不是null。通过原生的DOM方法获取JS原生对象获取不到的话,结果为null。)
$('.box a')后代选择器
$('.box>a')子代选择器第一个参数传递的如果是个元素对象,就是把JS原生对象转化为JQ对象
-
第一个参数传递的如果是个函数
(document).ready(function(){
这种写法和上面一模一样;
})
和window.onload有区别:
1、$(function(){})可以在同一个页面中使用多次,多次都生效(所以在使用JQ完成代码的时候,我们一般都会把代码放在回调函数中:首先不仅是等到结构加载完成再执行,而且还形成一个闭包)、
- 原理:
利用了DOM二级事件绑定(可以执行多次),监听的是DOMContentLoaded事件(DOM结构加载完成就会触发执行)2、window.onload本身就是资源都加载完成才会执行,使用的是DOM零级事件绑定,在同一个页面中只能使用一次;
- window.onload=function()...
- window.onload=function()...
只留最后一个
JQ对象和原生JS对象的相互转化
->把原生JS对象转化为JQ对象
var box=document.getElementById('box');
$box=$(box);//->$box存储的就是转化后的JQ对象
->把JQ对象转化为原生JS对象
var $body=$('body')
$body[索引]:获取集合中指定索引的原生JS对象(结果为原生JS对象)
$body.get(索引):等价于$body[索引]
$body.eq(索引):获取指定索引的JQ对象(结果为JQ对象)
JQ既是一个类也是一个对象
jQuery.prototype上设置了很多的属性和方法,这些是供JQ实例(DOM集合或者DOM元素)使用的属性和方法
$('a').index():获取当前元素的索引(是在自己兄弟元素中的索引,它有几个兄弟元素,索引就是几)
$('body').data(key,value)我们通过这个方法,可以获取到HTML结构上设置的data-xxx(前缀必须是data才可以用data方法获取到)的自定义属性的值
$('img').attr({src:"test.jpg",alt:"Test Image"}):设置或者批量设置或者获取当前元素的自定义属性(内置属性也可以)。如果是获取值,那么获取的值是字符串,如果需要用数值,则需要转化为number类型的;与removeAttr是一对。
设置的属性会在HTML结构上体现出来,attr的原理也是用内置的setAttribute来设置的;
$('.box').prop():和attr一样也是操作元素属性的,但是一般都操作表单元素的内置或者自定义属性 与removeProp是一对
$('.box').remove():从DOM中删除所有class名为box的元素。
addClass:增加样式类
removeClass:移除样式类
toggleClass:当前样式有就移除,没有就添加
$('.box').html(val):不传val就是获取内容,传递了就是设置,每次都会把原有绑定的数据先当字符串拿出来,等价于innerHTML
$('input').val(value):表单元素value值的操作(设置或者获取)
css:设置或者批量设置或者获取元素的样式(获取的结果是带单位的)
offect():获取距离Body的偏移量
position():获取距离父级参照物的偏移
$(window).width():获取到当前浏览器一屏幕的宽度(获取一屏幕的宽度只能用这个)
$(window).height():获取到当前浏览器一屏幕的高度(获取一屏幕的高度只能用这个)
innerWidth()/innerHeight():等价于clientWidth/clientHeight
outerWidth()/outerHeight():等价于offsetWidth/offsetHeight
$('#box').on('click',function...):JQ中的事件绑定
filter['fɪltə]:同级过滤
children:子代过滤器
$('#box').children('.bg')<=>$('#box>.bg')
find:后代过滤器
$('#box').find('.bg')<=>$('#box .bg')
JQ也是一个普通的对象
在对象上也有一些自己的属性和方法(和实例没有任何的关系),这些都是工具类的方法
$.ajax({
})
$.each({
})
引入多库$冲突的解决方法
var j=$.noConflict():
如果当前项目中引入了两个类库,都是使用$操作,为了防止$使用权的冲突,JQ可以让$的使用权转让;此处返回的j就是代表原始$的变量,以后可以使用j()执行,使用jQuery()执行也可以;
var j=$.noConflict(true):参数代表深度转让,true代表深度转让,false代表只转让$的使用权,默认为false
深度转让,代表jQuery的使用权也转让出去了;
each
jq中的each有两种,准确来说有三种
1、写在原型上的each:遍历JQ对象中的每一项
2、写在对象上的each:工具方法,可以用来遍历数组、类数组、对象等
1、内置的each循环
$('a').addClass('sel')=>相当于给每一个a都增加了sel这个样式类
$('a').css('width')=>获取的时候只返回第一个元素的样式
2、原型上的each
$('a').each(function(index,item){
参数传递顺序和原生JS中数组的forEach方法相反
index是当前遍历这一项的索引,item是当前遍历这一项的内容
this->item当前遍历的这一项(原生JS对象)
})
3、jQ对象上的each方法
$.each([数组\类数组],function(index,item){
this->item;
})
$.each([对象],function(key,value){
this->value;
JQ也是采用for in循环来遍历对象的,这样的话就可以把自己在原型上扩展的公有的属性和方法都遍历到;
})
extend
$.extend():把jQery当作一个对象扩展方法,这个操作一般是用来完善类库的
//把jQuery当成一个对象扩展方法;
$.extend({
aa:function(){}
});
$.aa();
$.fn.extend():把方法扩展到JQ的原型上,供JQ的实例使用,这个操作一般都是用来写JQ插件的
//把jQuery当作构造函数,扩展到jQuery的原型上供它的实例使用;
$.fn.extend({
bb:function(){
this->这里的this是操作当前这个方法的JQ实例(JQ对象),不需要再转换为JQ对象
}
})
$('xxx').bb();
animate
JQ中提供了元素运动的动画库
stop:结束当前元素正在运行的动画,从当前位置继续执行下一个新动画;
finish:停止当前的动画并直接让元素运动到目标位置,从目标位置执行下一个动画。
animate(target,duration,effect,callBack):
- target:目标值(是个对象)
- duration:多少毫秒完成
- effect:运动方式
- callBack:动画结束后做的事情
show
hide
toggle
fadeIn
fadeOut
fadeTo
fadeToggle
slideUp
slideDown
slideToggle
delay
23、事件
事件
事件是浏览器天生就赋予元素的行为,而不是通过代码添加给它的,当我们点击或者滑入滑出元素时,就已经触发了它的事件,只是我们没有给它赋予对应的操作而已;
PC端常用事件
1、表单常用事件行为
blur:失去焦点
focus:获取焦点
input:在 value 改变时触发
change:内容改变且失去焦点后触发
select:被选中事件
2、键盘常用事件行为
keydown: 键盘按下
keyup:键盘抬起
keypress :一直按着键盘而且文本框中有内容输入的时候才会触发;
3、鼠标常用事件行为
click:点击
dblclick:双击(300ms内连续触发两次点击事件,即双击事件)
mouseover:鼠标滑过
mouseout:鼠标离开
mouseenter:鼠标进入
mouseleave:鼠标离开
mousemove:鼠标移动
mousedown:鼠标左键按下
mouseup:鼠标左键抬起
mousewheel:鼠标滚轮滚动(无冒泡传播)
4、其他常用事件行为
load:加载成功
error:加载失败
scroll:滚动滚动条触发事件(无冒泡传播);
resize:window.onresize浏览器窗口的大小改变触发这个事件
移动端常用事件
移动端键盘事件
移动端的键盘一般都是虚拟键盘,虽然部分手机存在keydown/keyup但是兼容不好,所以我们想用键盘事件的时候,使用input事件代替
box.oninput=function(){};移动端手指事件
click(单击)、load、scroll、blur、focus、change、input(代替keyup keydown)
移动端的click事件是单击事件,但是click事件会有300ms的延迟,如果在300毫秒之内有第二次点击,就不属于click了,没有触发第二次点击才属于click
(如何解决?不用click)
单手指事件:
touchstart:手指按下
touchend:手指离开
touchmove:手指在屏幕上滑动
touchcancel:意外取消
事件绑定
给元素的某一个事件绑定方法,目的是为了让当前元素的某个事件触发的时候,我们给它对应的操作;
给元素的某一个事件绑定对应的方法,常用的有两种方法:
- 1、DOM0级事件绑定
box.onclick=function(){}
;
浏览器把click这个事件行为挂载到了当前元素的onclick这个私有属性上,我们绑定对应的方法是在给对应的属性赋值,所以当click行为触发的时候,当前元素的onclick所对应的方法就可以执行- 2、DOM2级事件绑定
标准浏览器:
box.addEventListener('click',function(){},false)
;
IE6-8:
box.attachEvent('onclick',function(){})
;
浏览器把click这个事件行为挂载到了内置的事件池所对应的事件类型上。我们可以通过addEventListener把click时需要执行的方法绑定到内置的事件池当中,当对应的事件行为触发的时候,浏览器会自动的到事件池中找到click类型下的方法来执行。
addEventListener这个方法是定义在元素所属EventTarget这个类的原型上的;
事件对象
当元素的某一个事件行为触发,不仅会把对应的方法执行,而且浏览器还会默认的给这个方法传递一个值当作方法的参数,我们把传递的这个值称为
事件对象
鼠标事件对象
1、因为这个值是对象数据类型的值,里面存储了很多的属性名和属性值,这些是用来记录当前鼠标操作的相关信息的。如:鼠标位置、触发的行为类型、触发的事件源等
2、MouseEvent记录的是页面中唯一一个鼠标当前操作的相关信息,和到底是在哪个元素上触发的没有关系。标准浏览器:
用addEventListener绑定方法:给所有方法中传递的e(MouseEvent)都是同一个对象,同一个内存地址,不同的是我们每次不同的操作都会重新获取同一个内存地址中不同的值;
在IE6-8下
用attachEvent绑定事方法:在给方法传递window.event之前,会先把window.event进行深拷贝一份,然后再传递给要执行的方法。所以我们每次操作重新获取的不是window.event中的值,而是拷贝后的window.event里面的值;
MouseEvent中的很多属性都是只读属性,只读属性只能拿来用,而不能赋值,如e.clientX,如果在标准浏览器中写e.clientX=20,不会报错,但是不起作用。下面的代码依然执行;但是在IE6-8下就会报错,下面的代码不再执行;
注意:
MouseEvent事件对象的获取在标准浏览器中是给方法传递的参数,我们只需要定义形参e就可以获取到。
如果用DOM0级事件绑定,在IE6-8下浏览器不会给方法传递参数,e的值为undefined,如过我们需要,则需要用window.event来获取。如果用DOM2级事件绑定,在IE6-8下浏览器会给方法传递参数,e的值就是window.event;
e.type:存储的是当前鼠标触发的行为类型
e.clientX/e.clientY:当前鼠标触发点距离当前窗口左上角的x/y轴的坐标值
e.pageX/e.pageY:当前鼠标触发点距离body最左上角的x/y轴的坐标值 (IE6-8下没有这两个属性)
e.target:事件源(当前点击的那个元素),当前鼠标触发的是哪个元素,那么它存储的就是那个元素。(IE6-8下不兼容,我们用e.srcElement来获取事件源)
e.preventDefault:阻止浏览器的默认行为;(IE6-8下不兼容,用e.returnValue=false 或者直接在函数中return false都可以阻止默认行为
e.stopPropagation:阻止事件的冒泡传播。(IE6-8下不兼容,使用e.cancelBubble=true来代替)
box.onclick=function(e){
console.dir(e);
e= e || window.event;
e.target=e.target || e.srcElement;
e.target:事件源(当前点击的那个元素),当前鼠标触发的是哪个元素,那么它存储的就是那个元素。(IE6-8下不兼容,我们用e.srcElement来获取事件源)
e.stopPropagation:阻止事件的冒泡传播。(IE6-8下不兼容,使用e.cancelBubble=true来代替)
e.type:存储的是当前鼠标触发的行为类型
e.clientX/e.clientY:当前鼠标触发点距离当前窗口左上角的x/y轴的坐标值
e.pageX/e.pageY:当前鼠标触发点距离body最左上角的x/y轴的坐标值 (IE6-8下没有这两个属性,下面有解决方法)
e.preventDefault:阻止浏览器的默认行为;(IE6-8下不兼容,用e.returnValue=false 或者直接return false都可以阻止默认行为
}
IE6-8不兼容处理
box.onclick=function(e){
if(typeof e==='undefined'){
//说明是IE6-8;
//处理e使用IE6-8下的window.event
e=window.event;
//处理事件源
e.target=e.srcElement
//处理e.pageX和e.pageY
e.pageX=e.clientX+(document.documentElement.scrollLeft||document.body.scrollLeft);
e.pageY=e.clientY+(document.documentElement.scrollTop||document.body.scrollTop);
//处理浏览器的默认行为
e.preventDefault=function(){
e.returnVaule=flase;
}
//处理冒泡传播
e.stopPropagation=function(){
e.cancelBubble=true;
}
}
}
键盘事件对象
KeyboardEvent
code:当前键盘的按键名称(IE6-8下没有这个属性);
which:和keyCode一样对应的也是键盘码的值(它不兼容IE6~8)
e.keyCode:当前键盘上的每一键对应的值(IE下只有这个)
空格(space):32
回退(Backspace):8
回车(Enter):13
删除(Del):46
四个方向键:左37 上 38 右39 下 40
[图片上传失败...(image-87a356-1541657333373)]
移动端手指事件对象
touches&changedTouches&targetTouches:存储的是当前屏幕上每一个手指操作的位置信息
touches:只有手指在屏幕上我们才可以获取对应的信息值(手指离开屏幕就没有相关信息了),这样就无法获取手指信息了;
changedTouches:手指在屏幕上的时候,和touches获取的信息一样,但是它可以记录手指离开屏幕一瞬间所在的位置信息(最常用);
TouchEvent
type:'touchstart',
target:事件源,
touches:
0:{
clientX:xxx,
clientY:xxx,
pageX:xxx,
pageY:xxx
}
length:1
移动端的click事件是单击事件,但是click事件会有300毫秒的延迟,如果在300毫秒之内有第二次点击,就不属于click了,没有触发第二次点击才属于click。
如何解决?
在移动端开发中,我们需要的一些操作(例如:点击、单击、双击、长按、滑动、左滑、右滑、上滑、下滑...)都是基于内置原生的touchstart/touchmove/touched事件模拟出来的效果
而多手指操作(如:旋转、缩放..)都是基于gesture事件模型模拟出来的效果
3、移动端事件库
->FastClick.js:解决CLICK事件300MS的延迟
->TOUCH.JS:百度云手势事件库 https://github.com/Clouda-team/touch.code.baidu.com
->HAMMER.JS
->Zepto.js:被誉为移动端的小型JQ
https://github.com/madrobby/zepto.git
http://www.bootcss.com/p/zeptojs/
ZEPTO专门的准备了移动端常用的事件操作:
tap(点击)、singleTap(单击)、doubleTap(双击)、longTap(长按)、swipe(滑动)、swipeUp(上滑)、swipeDown(下滑)、swipeLeft(左滑)、swipeRight(右滑)...
A标签的默认行为及阻止
a标签都有哪些默认的行为;
1、超链接:点击a标签实现页面的跳转
2、锚点定位:通过hash值定位到当前页面(或其他页面)的指定ID元素的位置;
3、阻止a标签默认跳转行为
阻止a标签的默认跳转行为
阻止a标签的默认跳转行为
如过a标签的href中有内容,那么点击a标签的时候,会先触发绑定的方法,再按href中的地址进行页面跳转
阻止a标签的默认跳转行为
link.onclick=function(){
return false
}
DOM2级事件流的三个阶段
1、捕获阶段:从外向里依次查找元素 ,查找到事件源为止,为截获事件提供了机会
2、目标阶段:执行当前操作的事件源所对应的方法
3、冒泡阶段:从内到外依次触发相关行为(我们常用的就是冒泡阶段),只能向上传播。
当前元素的某个事件行为被触发,他所有的祖先元素(一直到document)的相关事件行为也会被依次触发(顺序从内向外),如果祖先元素的这个行为绑定了方法,绑定的方法也会被触发执行,我们把事件的这种传播机制叫做:冒泡传播;
[图片上传失败...(image-60e8cd-1541657333374)]
mouseover和mouseenter的区别
mouseover:鼠标滑到元素上,存在事件的冒泡传播机制
mouseenter:鼠标进入元素里面,阻止了事件的冒泡传播机制
鼠标从父元素进入到子元素
mouseover:先触发父元素的mouseout事件(因为鼠标已经不在父元素上了,mouseover本意是鼠标在元素上才算触发),再触发子元素的mouseover,由于冒泡传播,还会触发父元素的mouseover事件
enter:进入,从大盒子进入到小盒子,没有触发大盒子的mouseleave事件,但是触发了小盒子的mouseenter事件,浏览器阻止了它的冒泡传播,所以大盒子的mouseenter不会被触发;
事件委托
利用了事件的冒泡传播机制(触发当前元素的某个行为,它祖先元素的相关行为都会被触发)
如果一个容器中的很多元素都需要绑定点击事件,我们没有必要一个个的绑定,利用事件的冒泡传播机制,只需要给最外层容器绑定一个点击事件即可。在这个方法执行的时候,通过事件源的区分来进行不同的操作;
好处:
1、事件委托性能比单独一个个绑定方法会提高50%;
2、可以给动态增加的元素也绑定事件jQuery中除了bind,on,click,mouseover这些绑定事件的方式外,还提供了一种delegate(1.7以前用的是live)方法,我们用delegate方法完成jQuery中的事件委托;
$menu.delegate('h3','click',function (e) {})
第一个参数是选择器,第二个参数是触发事件,第三个参数是绑定的方法,传入的e为事件对象,jQuery中已经处理了e 的兼容问题;
on方法和delegate都可以实现事件委托,用on 方法要自己判断事件源,delegate只是不需要判断事件源了而已;
24、DOM2级事件
DOM0级事件绑定
原理:
1)onclick是元素对象的一个私有属性,在给元素的click行为绑定方法的时候,就相当于在给元素的onclick这个属性赋值;重复给元素的同一个事件绑定方法,就相当于把之前的值替换掉,只能执行最后一次绑定的方法。行为触发的时候就会执行对应的方法;为什么给onclick赋值后,点击的时候就可以执行对应的方法?
click、mouseover、mouseout、mouseenter、mouseleave...对于这些事件行为,浏览器会把一些常用的事件行为挂载到元素对象的私有属性上如onclick属性,让我们可以实现DOM0级事件绑定;
DOMContentLoaded属于DOM2级事件,浏览器没有把它挂载到元素对象的私有属性上,所以不能用DOM0级事件来绑定对应事件的方法;
在IE6-8下使用DOM0级事件给元素绑定方法,方法执行的时候,不会传入事件对象e,我们要用window.event来获取;
DOM2级事件绑定
原理:
浏览器把click这个事件行为挂载到了内置的事件队列中所对应的事件类型上。我们通过addEventListener给元素绑定方法时,浏览器会在事件队列当中,按照事件行为的不同,把绑定的方法存放到对应事件行为下。当对应的事件行为触发的时候,浏览器会自动的到事件队列中找到click类型下的方法,按照绑定的顺序,依次执行;
addEventListener这个方法是定义在元素所属EventTarget这个类的原型上的
优点:可以给元素的某个事件行为绑定多个不同的方法,如果方法相同(即指向的空间地址相同),则不再重复绑定;
var obj={
fn1:function () {
console.log(1);
}
};
document.body.addEventListener('click',obj.fn1,false);
obj.fn1=function () {
console.log(2);
};
document.body.addEventListener('click',obj.fn1,false);
//在这个地方点击body的话会输出1,2,因为两个addEventListener中绑定的方法内存地址不是同一个所以两次都会绑定;
document.body.removeEventListener('click',obj.fn1,false);
//上一步移除只能移除输出2的这个函数,因为obj.fn1的地址已经更改为输出2的这个地址,所以点击的时候只输出1,不会输出2;
addEventListener(事件类型,方法,阶段[true,false]) IE6-8下不兼容
true代表在捕获阶段执行方法,false代表在冒泡阶段执行方法attachEvent(事件类型(要加on),方法)/detachEvent(事件类型,方法) IE6-8下绑定事件
不能控制在哪个阶段发生,只能在冒泡阶段发生;
box.attachEvent('onclick',function(e){
此处的e为IE6-8下的window.event,所以还要处理兼容的问题,
e=window.event;
target=e.srcElement
e.pageX/e.pageY:IE6-8下没有;
//兼容处理
e.pageX=e.clientX+(document.documentElement.scrollLeft||document.body.scrollLeft);
e.pageY=e.clientY+(document.documentElement.scrollTop||document.body.scrollTop);
e.preventDefault=function(){
return false;
}
e.stopPropagation=function(){
e.cancelBubble=true;
}
})
DOM0和DOM2的区别
1、给元素的同一个事件绑定多个方法
DOM0不能,如果绑定多个,会按最后绑定的那一个来执行;
DOM2可以,可以绑定多个不同的方法,但是如果绑定方法的内存地址相同(即同一个方法),则不会再绑定;
2、执行顺序
同一个事件类型,按绑定的顺序来执行,DOM0和DOM2没有执行顺序区别,谁先绑定谁先执行;
3、所有DOM0支持的事件行为,DOM2都可以使用,不仅如此,DOM2还支持一些DOM0没有的事件行为:DOMContentLoaded...DOMContentLoaded是一个DOM2级事件行为;
标准浏览器中兼容这个事件:当浏览器中的DOM结构加载完成,就会触发这个事件(也会把绑定的方法执行)
window.onload和$(document).ready()的区别
window.onload
当浏览器中所有的资源内容(DOM结构、文本内容、图片……)都加载完成,会触发load事件
1、它是基于DOM0级事件绑定的,所以在一个页面中只能给它绑定一个方法,如果绑定多个方法,会按最后一个绑定的方法执行
2、如果想在页面中执行多次,应该基于DOM2级来绑定;
$(function(){})
或 $(document).ready(function(){})
当文档中的DOM结构加载完成就会被触发执行,而且在同一个页面中可以使用多次
1、上面两个是JQuery中提供的方法。JQ是基于DOMContentLoaded这个事件完成这个操作的
2、JQuery中的事件绑定都是基于DOM2事件绑定完成的
3、但是DOMContentLoaded在IE6-8下使用attachEvent也是不支持的,JQ在IE6-8下使用的是readystatechange这个事件来处理的;
区别
1、window.onload是基于DOM0级事件来绑定的 ,$(function(){})和$(document).ready(function(){})是基于DOM2级事件来绑定的;
2、由于window.onload是采用DOM0事件绑定,所以不能触发多次,只会触发一次。而$(function(){})和$(document).ready(function(){})是基于DOM2级事件绑定的,所以可以执行多次,按照绑定的顺序执行;
3、由于window.onload是采用DOM0事件绑定,所以不能绑定多个方法,绑定多个也会按最后一个执行,而$(function(){})和$(document).ready(function(){})是基于DOM2级事件绑定的,所以可以绑定多个不同的方法,执行的时候按照绑定的顺序依次执行;
DOM2级事件绑定的兼容处理
addEventListener和attachEvent的区别
除了语法上的区别,在处理的机制上有一些区别,在IE6-8下,使用attachEvent做事件绑定(把方法存放在当前元素指定事件类型的事件队列中)时与addEventListener的区别:
1、顺序问题:当事件行为触发,执行对应事件队列中存放的方法,IE低版本浏览器执行方法的顺序是乱序(标准浏览器是按照绑定的先后顺序依次执行的)
2、重复问题:IE低版本浏览器中在向事件队列中添加方法时,即使是同一个方法,也会重复的添加;(标准浏览器的事件池机制很完善,可以自动去重,方法内存地址相同则不会再添加);
3、this问题:IE低版本浏览器中,事件行为触发,对应方法执行的时候,方法中的this是window,而不像标准浏览器中那样,this指向当前元素本身;
以上问题的根本原因:IE低版本浏览器中内置的事件队列处理机制不完善导致的;
解决方法:自己模拟事件队列,只需要处理IE6-8的事件队列,标准浏览器是不需要处理的
25、CSS3与H5
CSS3
新增了很多的选择器
属性选择器:
a[src^="https"]:选择其 src 属性值以 "https" 开头的每个 元素。
a[src$=".pdf"]:选择其 src 属性值以 ".pdf" 结尾的每个 元素。
a[src*="abc"]:选择其 src 属性中包含 "abc" 子串的每个 元素。
伪类选择器:
.page2 img:nth-child(1){} :先获取page2下的第一个子元素,然后再判断这个子元素的标签是否是img,不是img则不会生效
.page2 img:nth-of-type(1){} :先获取page2下的标签名为img元素,再找到其中的第一个元素;
:not(p):选择除了p元素以外的元素
新增一些常用的属性
border-radius:盒子圆角
一个值: 四个圆角值相同
两个值: 左上与右下,右上与左下
三个值: 左上, 右上和左下,右下
四个值:左上,右上,右下,左下
box-shadow:盒子阴影
box-shadow: x-shadow y-shadow blur spread color inset;
x-shadow: 水平阴影(必须的,正值靠盒子右,负值靠盒子左)
y-shadow:垂直阴影(必须的,正值靠下,负值靠上)
blur:模糊程度(可选,值越大越模糊)
spread: 阴影尺寸(可选,越大阴影越大)
color:阴影的颜色(可选)
inset:将外部阴影 (outset) 改为内部阴影(可选)
text-shadow:文本阴影
text-shadow: x-shadow y-shadow blur color;
x-shadow:必需。水平阴影的位置。
y-shadow:必需。垂直阴影的位置。
blur: 可选。模糊程度(可选,值越大越模糊)
color:可选。阴影的颜色。
text-indent 首行缩进(1em相当于一个字体大小,2em相当于两个字体大小)
word-break :让页面文字自动换行
word-wrap :长单词或URL地址自动换行
css原有属性 :white-space:nowrap;文本不会换行直到遇到
标签
text-overflow :clip
内容溢出时溢出内容被裁切掉 或 ellipsis
[ɪ'lɪpsɪs]以省略号的形式展现出来
...
关于背景的升级
background:rgba (颜色透明)
background:-webkit-linear-gradient / radial-gradient (背景色渐变):如何不让它渐变(变成一道一道的):
background: -webkit-linear-gradient(left bottom,#5CB85C 0%,#5CB85C 25%,#74C274 25%,#74C274 50%,#5CB85C 50%,#5CB85C 75%,#74C274 75%,#74C274 100%);
background-size:指定背景图片大小。值可以为 百分比 具体数值 cover(以最适合的比例铺满整个屏幕)
background-clip:规定背景的绘制区域
background-origin:规定 background-position 属性相对于什么位置来定位。
...
-webkit-filter滤镜的升级
变形:transform
translate():根据左(X轴)和顶部(Y轴)位置给定的参数,从当前元素位置移动。 —— 2D转换
transform: translate(50px,100px);
当前元素原来位置向右移动50个像素,向下移动100像素
rotate() :在一个给定度数顺时针旋转的元素。负值是元素逆时针旋转。 ——2D转换
rotateX():让元素围绕X轴旋转——3D转换
rotateY() :让元素围绕Y轴旋转——3D转换
rotateZ():让元素围绕Z轴旋转——3D转换
transform: rotate(30deg);
当前元素顺时针旋转30度
transform: rotateX(60deg);
当前元素绕X轴旋转60度
transform: rotateY(60deg);
当前元素绕X轴旋转60度
scale()[skeɪl]:该元素增加或减少的大小,取决于宽度(X轴)和高度(Y轴)的参数:
transform:scale(2,3)转变宽度为原来的大小的2倍,和其原始大小3倍的高度。
skew()(很少用):分别表示X轴和Y轴倾斜的角度
matrix(很少用)
...
transform-style:嵌套元素是怎样在三维空间中呈现。
transform-style:preserve[prɪ'zɜːv]-3d(表示所有子元素在3D空间中呈现。)
flat(表示所有子元素在2D平面呈现。)
transform-origin:改变元素的中心点
CSS3动画
1、transition:过渡动画
下面为简写方式
transition: width 1s linear 2s;
transition-property:需要过渡的 CSS 属性的名称。
transition-duration:完成过渡效果花费的时间。默认是 0。
transition-timing-function:规定过渡效果的时间曲线。默认是 "ease"。(可不写)
transition-delay [dɪ'leɪ]:过渡效果延迟多久开始执行。默认是 0;(可不写)
2、animation:帧动画
css3中我们使用@keyframes来设置一个动画的关键帧,用animation来执行动画
@keyframes 动画名称{
0%{
}
100%{
}
}
以下为连写
animation: move 1s linear infinite both;
animation-name:运动轨迹的名称(@keyframes设置运动轨迹)
animation-duration: 完成动画需要的总时间;
animation-timing-function: 运动方式,默认为为匀速;
animation-delay [dɪ'leɪ]: 延迟时间,延迟多少秒后执行;(可不写)
animation-iteration-count: 动画重复的次数,默认执行一次,infinite是无限次运动;
animation-fill-mode: 设置动画的状态;默认值为none;
none默认值:无任何特殊状态设置
forwards:动画完成后会停留在最后一帧的位置;(默认动画完成后会回退到起始位置)
backwards:在延迟的情况下才有用,当动画在延迟时间内,让运动的元素在运动轨迹的第一帧位置等待
both:同时具备以上两个效果;
CSS3中的盒子模型
1、box-sizing:border-box(宽度包括内部白及边框)或content-box(默认的都是不包括内部白及边框);
2、flex
CSS3中的@media
需要写两套加-webkit-前缀的CSS3属性(兼容IOS和安卓)
transition、animation、@keyframes、transfrom、gradient、flex……
H5
HTML5基础
HTML:超文本标记语言(页面中不仅只有文字,而且可以呈现出图片,音视频等媒体资源)
XHTML:它是HTML比较规范严谨的一代版本;
XML:可扩展的标记语言(HTML中使用的标签都是W3C标准中规定的,XML 允许我们自己扩展标签),它不是用来写页面结构的,而是用来存储一些数据的(以自己扩展的标签作为标识,清晰明了的展示出数据的结构)
HTML5:当前HTML最新的一代版本,也是非常成功的一代版本,目前市场上基本都是基于H5规范进行开发的(它相对于传统的HTML更多的是增加了一些有助于开发的内容,对原有的规范的修改调整很少)
HTML5文档声明
声明页面的语言模式,如果页面中出现英文会主动提示你是否翻译
采用国际统一编码UTF-8模式;
GBK(GB2312)中国编码
;
HTML5提供的新语法规范
对原有语义化标签的升级
标签语义化:每一个HTML标签都有自己特殊的含义,我们在搭建页面结构的时候,应该让合理的标签做合适的事情
HTML5中新增的语义化标签(默认都是块级元素)
main:主体内容
section:一个主体性内容区域,通常包含一个头部,可能还有一个尾部;
header:头部区域,放在页面顶部的内容,或着放在页面某个区块的顶部
nav:导航区域
article:文章区域,表示页面中一个独立的组成部分,如一个博客帖子或新闻报道
aside:与主体内容无关的区域(一般用来打广告)对页面内容的补充,如插图或边栏
footer:尾部区域,放在页面底部的内容,或着放在页面某个区块的底部
figure:配图区域,通常包括图片和文字说明(figcapiton)
figcapiton:配图说明区域
H5中新增加的标签
mark:用来标记需要高亮显示的文本。如:milk
time:用来标记日期文本
H5中对原有标签的修改
1、修改的标签
small:显示为更小的文本。在HTML5中,定义旁注信息,并显示为更小的文本。
strong:定义加粗的被强调的文本,在HTML5中,定义重要的文本。
2、移除的标签
font
center
big
tt
在PC端开发或在移动端开发,我们更应该用H5规范的语义化标签搭建页面的结构
但是在IE6-8下不能识别这些新增加的语义化标签,我们无法为其设置具体的样式
解决:
在当前页面中的head中(css后),我们导入一个JS插件:html5.min.js,它就是用来把页面中所有用到的不兼容的H5语义化标签进行兼容处理
1、把页面中所有不兼容的标签进行替换
2、把css中使用标签选择器设置的样式(标签是H5标签)也替换成其他方式标准浏览器中不需要引入此html5.min.js。所以可用
条件注释
(只能在IE下起作用)来解决这个问题
H5中对于表单元素的升级
传统表单元素
form
input:ext、password(暗文输入)、button、submit、reset、file、hidden、radio、checkbox
button
select
label
textarea
submit:有默认行为,点击按钮会跳转到form的action对应的地址(表单提交);
现有前后端完全分离的项目中,我们都是在JS中手动获取到用户输入的内容,并且通过ajax等技术发送给服务器存储或者处理(此时我们要阻止submit的默认行为)H5的表单升级
1、给input设置了很多新的类型
search
email:提供了CSS伪类默认验证是否为基本的邮箱格式;
:vaild{
输入的文本是邮箱格式做的事
}
:invaild{
输入的文本不是邮箱格式做的事
}
telephone
number
range(滑动杆)
color(颜色板)
data(日历)
time(时间)好处:
- 1、功能强大
- 2、使用合适的类型,在移动端开发的时候,用户输入,可以调出最符合输入内容格式的虚拟键盘,方便用户操作
- 3、部分类型提供了表单验证(内置验证机制:和我们自己写的表单验证不太一样,但是可以凑合用,css验证和js验证都可以)
2、给input新增了一个属性:placeholder,给表单框做默认的信息提示,输入有内容时默认提示消失(IE10及以上虽然兼容但是文本框获取焦点后,提示信息就消失了,IE9及以下不兼容此属性)
3、二级下拉框(select一级下拉框)
H5展对于表单元素升级的部分,在IE低版本(有的IE9和10都不兼容)中不兼容,而且没办法处理兼容,所以我们只在移动端使用这些新特性,在PC端的表单验证我们用正则验证完成;
H5中其他新增内容
增加了新的媒体解决方法
音频:audio
视频:video
H5中的audio
音频播放标签,通过它可以播放音频文件(支持格式: mp3、ogg、wav)
使用
Audio中常用的一些内置属性
controls:是否使用内置的播放器播放,默认是不显示浏览器自带播放器的,加上这个属性显示
autpplay:自动播放
preload:设置当前音频文件预先加载的模式,默认为auto
- auto - 当页面加载后载入整个音频
- meta - 当页面加载后只载入元数据
- none - 当页面加载后不载入音频
loop:播放完成后循环播放
传统的音视频播放是基于flash来完成的,需要浏览器中安装abobe flash player插件
现在只需要基于 audio和video播放即可,但是对于音视频的格式有限制
移动端对于flash的支持不好,但是基本上都支持audio和video
PC端的IE浏览器(低版本)不支持audio和video,但是支持flash;
H5中增加了canvas(绘图)
它是一个画布,允许我们在JS中通过代码绘制图形以及一些好玩的动画
应用:百度统计图插件Echarts;
提供很多强大的JS API
API:Application Programming Interface 应用程序接口(凡是提供一个供别人使用的都可以称之为接口,例如:使用AJAX从服务器端获取数据,需要一个URL地址,此地址就是一个API,浏览器提供给我们很多常用的方法,每一个方法都可以叫做API)
本地存储
webStorage:
localStorage:永久存储到客户端的本地
sessionStorage:信息的会话存储,会话窗口存在信息也存在,会话窗口关闭信息就消失了
获取本机地理位置
通过H5可以获取到当前用户地理位置(经度、纬度、经纬度……),再结合第三方地图(高德地图、百度地图、腾讯地图……)API接口,实现一些生活服务的推荐
提供了新的通信方式:websocket
提供操作手机硬件功能的api
调取手机的重力感应器,实现摇一摇,或者实现一些小游戏
调取手机的摄像头或者通讯录等
不是所有的手机都支持这些功能,即使支持这些功能的浏览器,在实现效果上也是不理想的(会卡顿);
离线缓存
:manifest
第一次联网请求完成页面,把信息缓存到本地,下一次即使断网的情况下,也可以看到上一次的信息
26、JS中常用的设计模式
设计模式的好处
对于开发来说
开发效率高,利于团队协作,逻辑清晰,代码严谨,可维护、可扩展性高。依托设计模式可以实现组件化,模块化、插件化、框架化以及一些常用类库方法的编写
插件、组件、类库、框架的区别
类库:提供一些真实项目开发中常用的方法(方法做了完善 处理:兼容处理,细节优化),方便我们开发和维护如JQuery、Zepto
插件:把项目中某一部分进行插件化封装(具备一些具体业务逻辑的,更有针对性),以后再有类似的需求,直接导入插件即可,相关业务逻辑代码不需要自己再编写了
jquery.drag.js
jquery.dialog.js
datepicker日历插件
echars统计图插件组件:类似于插件,但是插件一般只是把JS部分封装了,组件不仅封装了JS部分,而且把css部分也封装了,以后再使用的时候,我们直接的按照文档使用说明引入css、js,搭建对应的结构,什么都不用做功能自然就有了;swiper组件、bootstrap组件
框架:比上面的三个都庞大,不仅提供了很多常用的方法、而且也可以支持一些插件的扩展(可以把一些插件集成到框架中运行),更重要的是提供了非常优秀的代码管理设计思想;
常用的设计模式
单例设计模式、构造函数设计模式、发布订阅设计模式、promise设计模式
单例设计模式
把实现当前模块所有的属性和方法汇总到同一个命名空间下(避免了全局变量的污染)
let Render=(function(){
return {
init:function(){
//控制当前模块中具体的业务逻辑顺序
}
}
})();
Render.init();
想要实现具体的业务逻辑需求,都可以依赖于单例模式构建:我们把项目划分成各大板块或者模块,把实现同一个模块的方法放在同一个独立的命名空间下方便团队协作开发
构造函数设计模式
class Tool{
constructor(){
this.flag='getComputedStyle' in window;
}
//挂载到原型上的方法
css(){
}
static distinct(){
}
}
class A extends Tool{
constructor(){
super();
this.xxx='xxx';
}
//写在原型上的方法
bindData(){
//可直接在此处使用父类原型上的方法
this.css();
//把父类当作对象添加的静态方法子类的实例是无法调用的;
this.distinct();//会报undefined
//想调用父类当作对象添加的方法
Tool.distinct();//不会报错
}
}
发布订阅模式(观察者模式)
达到某个条件之后,要执行N个方法,我们都可以依托于发布订阅设计模式管理和规划我们的JS代码;
原理:
1、先创建一个容器
2、后期要做什么事,我们都把要处理的事情增加到容器中
3、当达到某个条件的时候,我们只需要让容器中的方法按照顺序依次执行即可;
jQery中的发布订阅模式
let $plan=$.Callbacks();//创建一个容器
let fn2=function(){
};
let fn1=function(){
}
//把需要执行的方法添加到容器中
$plan.add(fn2);
$plan.remove(fn2);
//让容器中的方法依次执行100,200是让方法执行传递给方法的参数
$plan.fire(100,200);
promise设计模式
解决AJAX异步请求层级嵌套的问题;
目的是为了解决层级嵌套的问题
$.ajax({
url:'A',
async:true,
success:function (data) {
$.ajax({
url:'B',
async:true,
success:function (data) {
}
})
}
})