揭秘JavaScript高手不为人知的jq秘密

发表时间: 2020-08-04 22:08

JQuery

什么是

第三方的极简化的DOM操作函数库


为什么

1. DOM操作的终极简化

核心DOM: 万能, 但繁琐

HTML DOM: 简单,但不是万能

jQuery: 对DOM操作的终极简化

1. DOM操作

增,删,改,查

2. 事件

3. 动画效果

4. Ajax

2. 屏蔽了浏览器兼容性问题

凡是jQuery允许使用的,都屏蔽了兼容性问题

如何:

版本

1.x

兼容旧浏览器

.js

未压缩过的代码

可读性好

学习用

.min.js

压缩版本

毫无可读性

删除注释

去掉换行和空字符

极简化变量名

2.x 和 3.x

不再兼容旧浏览器

先引入jquery.js, 再编写自定义脚本

2种方法

1. 将jquery.js下载到服务器本地,在script中使用服务器路径

2. 使用CDN网络上共享的jquery.js

内容分发网络

可根据客户端到服务器的网络状况和访问量智能选择最优的服务器下载资源

生产环境中用的最多

原理

向全局添加了一种jQuery新类型

jQuery构造/工厂函数

创建jQuery类型的子对象

1. 查找,并封装jQuery对象

2. 将DOM元素封装为jQuery对象

其实可简写为:$("selector"|DOM)

window.jQuery=window.$=jQuery

jQuery.fn原型对象

是所有jQuery对象的父对象

封装了所有简化版API

jQuery对象

封装DOM对象的类数组对象,并提供对DOM对象执行操作的简化版API

为什么

DOM对象不包含,也不能使用jQuery简化版API

因为不是jQuery类型的子对象

只有将DOM对象封装进jQuery对象后,才能使用简化版API

如何

2种

1. 用$("selector")直接查找

返回包含找到的DOM对象的集合

jQuery对象

2. 如果已经获得一个DOM对象

先用$(DOM对象)封装DOM对象为jQuery对象

比如:

this, e.target

DOM对象

$(this), $(e.target)

jQuery对象

强调:

1. 尽量减少使用$(...)的次数

每$(...)一次就新创建一个jQuery对象

2. 尽量减少查找的次数

所有查找都是遍历,反复查找,效率低

解决

1. 如果一个jQuery结果对象可能被反复使用,就临时保存在变量中

2. 使用链式操作

查找

按选择器查找

基本选择器

同CSS

#id .class element * 选择器1,选择器2

层次选择器

同CSS

父级 后代 > + ~

过滤选择器

子元素过滤

同CSS

在父元素内编号

:first-child

:last-child

:nth-child(i/odd/even/2n/2n+1)

强调:

下标从1开始,且仅限于当前父元素内

:only-child

基本过滤(位置过滤)

先将符合条件的所有元素保存在一个集合中再统一编号

和元素在其父元素下的位置无关

:first/last

选择结果集合中第一个/最后一个元素

:even/odd

选择结果集合中下标为偶数或奇数的元素

强调:

下标从0开始

:eq/gt/lt(i)

选择结果集合中下标等于/大于/小于i位置的元素

否定选择器:

:not(任意selector)

属性过滤

同CSS

[属性名]

[属性名=值]

[属性名!=值]

:not([属性名=值])

[属性名^=开头]

[属性名$=结尾]

[属性名*=值]

selector1selector2...

而且

内容过滤

:contains(文本)

按元素的内容文本

:has('selector')

按子元素的特征来选择父元素

:empty

:parent

:not(:empty)

可见性过滤

:visible

:hidden

display:none

input type="hidden"

表单过滤

:input

input, select, textarea, button

如果只想查找一种表单元素

可用元素选择器

:type属性

:text :password :checkbox :radio :button :submit :reset :image :file :hidden

状态过滤

同CSS

:disabled :enabled :checked :selected

节点间关系

父子关系

$("...").parent()

获得当前元素的父元素

$("...").children(["selector"])

仅找*直接*子元素中符合selector条件的

$("...").find("selector")

在*所有后代*中查找符合selector条件的

$(...).children().first()

:first-child

$(...).children().last()

:last-child

兄弟关系

$("...").next/prev(["selector"])

紧邻的前一个或后一个兄弟元素

必须紧邻

$("...").nextAll/prevAll(["selector"])

之后/之前所有符合条件的兄弟

$("...").siblings(["selector"])

除自己之外的所有兄弟

API通用特点

1. 自带forEach的效果

对$("...")结果对象执行的操作,相当于自动应用到结果中每个元素上

2. API两用

没给新值,就读取属性值;给了新值,就是修改属性值

3. 每个API都再次返回结果对象本身

$("...")之后可使用链式操作反复调动多个API

为什么链式操作

1. 避免重复创建jq对象

每次调用$都会创建新的jq对象

2. 减少查询次数

3. 节省变量的使用

修改

内容

html内容

$("...").html(["html代码片段"])

两用

文本内容

$("...").text(["文本内容"])

两用

表单元素内容

$("...").val(["值"])

两用

清除内容

$("...").empty()

属性

访问标准属性

获取

var value=$("...").attr("属性名")

修改

只修改一个属性

$("...").attr("属性名",值)

同时修改多个属性

$("...").attr({ 属性名:值, 属性名:值, })

访问三大状态

包括: disabled checked selected

$("...").prop(...)

用法同attr()

另见:

移除属性

$("...").removeAttr/removeProp("属性名")

自定义扩展属性

$(...).data()

样式

直接修改css属性

获取css样式(计算后的样式)

$("...").css("css属性名")

相当于getComputedStyle

修改css样式

只修改一个css样式:

$("...").css("css属性名",值)

相当于elem.style

为每个元素的css属性动态生成不同的值

$("...").css("css属性名", function(i){return 值})

i会依次获得每个元素的下标

返回值会被依次设置到每个元素的指定css属性

同时修改多个css样式:

$("...").css({ css属性名:值, css属性名:值, ... })

强调:

所有CSS属性名都要去横线变驼峰

纯数字的属性值不必加单位

通过修改class批量修改样式

判断是否包含指定class

$("...").hasClass("类名")

添加class

$("...").addClass("类名")

移除class

$("...").removeClass("类名")

切换class

$("...").toggleClass("类名")

if(.hasClass(...)) .removeClass(...) else .addClass(...)

添加,删除,替换和复制

添加

1. 创建新元素

var $newElem=$("html代码片段")

2. 将新元素添加到DOM树

结尾/开头插入

$(parent).append/prepend($newElem)

在某个child前后插入

$(child).before/after($newElem)

简写:

$(parent).append("html代码片段")

删除

$("...").remove()

替换

$("现有元素").replaceWith("新元素html代码")

用右替换左

$("新元素html代码").replaceAll("现有元素")

用左替换右

克隆

$("...").clone()

浅克隆

仅复制属性,不复制行为

$("...").clone(true)

深克隆

即复制属性,又复制行为

事件

鄙视

jQuery中共有几种事件绑定方式

.bind/unbind("事件名",fn)

.unbind('事件名',fn)

.unbind('事件名')

.unbind()

.one("事件名",fn)

废弃

$("selector").live/die("事件名",fn)

利用冒泡

$("parent").delegate("selector","事件名",fn)

简化了利用冒泡中:

1. 用参数selector代替了if判断

2. this->e.target

$(...).undelegate(...)

鄙视题:

bind vs delegate

1. bind直接帮在触发事件的目标元素(子元素)上

delegate绑定在触发事件的元素的父元素上

2. 事件监听个数不一样

bind是每个子元素都添加事件监听

delegate只为父元素添加一个事件监听

3. 动态添加的元素

bind绑定时,要求触发事件的元素必须已经存在

delegate可为父元素下动态添加的子元素提供事件监听

简化

仅为一个元素绑定事件

$("...").on("事件名",fn)

bind

利用冒泡/事件委托

$("parent").on("事件名","selector",fn)

delegate

$(...).off(...)

同unbind/undelegate

终极简化版

$("...").事件名(function(e){...})

this

普通事件绑定

this->触发事件的当前元素

利用冒泡

this->e.target

DOM对象

$(this)

jq对象

模拟触发

$("...").trigger("事件名")

模拟触发所有选中元素的指定事件

可简写为

$(...).事件名()

页面加载后触发

只要DOM内容加载完成就触发

DOMContentLoaded

只要等待HTML , js

$(document).ready(fn)

domcontentloaded

$().ready(fn)

$(fn)

整个页面加载完才执行

等待HTML,CSS,JS,图片...

window.onload=function(){...}

其实

只要将script代码放在body结尾就可以实现DOM加载后就执行

鼠标事件

mouseover vs mouseenter

mouseover

进出子元素,同样会触发父元素的mouseover

mouseenter

进出子元素,不会再触发父元素的mouseenter

mouseout vs mouseleave

.hover

等效于同时绑定两个事件: mouseenter和mouseleave

如何

.hover(fn_enter, fn_leave)

如果fn_enter和fn_leave的行为可统一成一样的

简写

.hover(fn)

fn即响应enter,又响应leave

事件处理函数中传入参数

$(...).on("事件名",data,fn)

其中data: {属性名: 值, ...}

读取

fn中

e.data.属性名...

动画效果

简单:

显示隐藏

$("...").show/hide/toggle(speed,easing,callback)

如果没有参数

默认不带动画,用display控制瞬间显示和隐藏

上下滑动

$("...").slideUp/slideDown/slideToggle(speed,easing,callback)

淡入淡出

$("...").fadeIn/fadeOut/fadeToggle(speed,easing,callback)

问题:

不便于维护

使用程序的定时器实现,效率比css动画低

解决

其实都应该用

class + transition

动画结束后执行

每个动画函数的最后一个参数都是一个回调函数,专门在动画结束后自动执行

回调函数中的this->指正在执行动画的DOM对象

万能

$("...").animate({ css属性: 目标值, css属性: 目标值, ... },speed,easing,callback)

多个css属性并发改变

问题

仅对单数值的属性有效

对颜色,字体,C3的变换...无效

排队和并发

并发

1. 放在一个animate中的多个css属性

2. 对不同元素同时执行animate时

排队

对一个元素先后调用animate

$("...").animate().animate()...

会创建动画队列,依次排队执行

停止:

$(...).stop()

仅停止当前正在执行的动画

队列中后续动画依然执行

$("...").stop(true)

停止当前正在执行的动画

清空动画队列

延迟执行

.delay(ms)

setTimeout

选择器:

:animated

匹配所有正在执行动画效果的元素

问题:

底层依然是定时器动画,效率低

解决:

animate.css

类数组对象操作

$(...).get(i)

获得jQuery对象中i位置的DOM元素对象

$(...).size()

获得jQuery对象中封装的DOM元素个数

$(...).each(fun)

对jQuery对象中每个DOM元素执行相同的操作

$(...).each(function(i){ //this->正在遍历的DOM元素 })

$(...).index()

查找指定DOM元素在jQuery对象中的存储位置

用法:

1. $("selector").index(jq对象|DOM对象)

在左边找到的jQuery结果集合中,找右边对象的位置

2. $("selector").index("selector")

在右边的查找结果集合中,找左边选中的元素的位置

3. $("selector").index();

查找当前元素在其父元素下的下标位置

封装自定义插件

添加jQuery对象函数

如果jQuery的简化版API不够用,可自定义API

如何:

1. 判断是否引入jQuery

if(typeof jQuery!="function") 就报错

2. 向jQuery.fn原型对象中添加自定义函数

jQuery.fn.自定义API=function(){ this->将来调用该API的jQuery对象,不用再用$()封装 }

封装自定义Widget

封装

前提:

使用html, css, js, jquery成功实现过部件的完整效果

Step1:

css拷贝到部件的css文件中

尽量少的使用元素名和id

应该用class和自定义扩展属性代替

Step2:

添加js文件

1. 判断是否提前加载了jQuery

if(typeof(window.jQuery) !=="function") throw new Error(...)

2. 为jQuery.fn添加实例方法

向当前元素及其子元素上侵入class或data-*扩展属性

为data-*的元素绑定事件

使用

1. 引入部件css

2. 按部件要求编写HTML内容

3. 引入jquery

再引入部件js

4. 自定义脚本

查找父元素,调用部件函数