Math.max(0, startTime + options.duration - createTime()) 过滤出数组最大值
+new Date 时间戳
onceRun =
function(func) {
makeAnim(element, options, func);
}
func =
function() {
fireing = false;
_fire();
}
在 ajax 请求中类型如果是 type 是 post,其实内部都只会用 get,因为其跨域的原理就是用的动态加载 script 的 src,所以我们只能把参数通过 url 的方式传递
我们使用了 dataType 是 'jsonp' 但是 jquery 内部有进一步的优化,如果探测到还是同域下的请求,依然还是用 XmlHttpRequest 处理,所以我们在同域下测试的话,可以把 crossDomain 选项置为 true,这样强制为跨域处理,这样就会通过 script 处理了
jsonp: "callback", //传递给请求处理程序或页面的,用以获得jsonp回调函数名的 参数名(一般默认为:callback)
jsonpCallback: "Handler", //自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据
如果 on 中传入参数 selector ,意味着就是有委托的处理,那么我们就需要用一个标记来记录下这个元素到底委托了多少次。
event 对象的属性和方法包含了当前事件的状态。
当前事件,是指正在发生的事件;状态,是与事件有关的性质,如引发事件的 DOM 元素、鼠标的状态、按下的键等等。
如上结构,currentTarget 是 aaron 的 div 元素 , target 是 p 元素,事件对象是有作用域的 currentTarget 是等于 this 的。
e.stopImmediatePropagation 方法不仅阻止了一个事件的冒泡,也把这个元素上的其他绑定事件也阻止了。
事件对象提供了 preventDefault,stopPropagation2 个方法一个停止事件传播,一个传递默认的行为(暂且无视IE),
在下列情况下,应该使用 .live()或 .delegate(),而不能使用 .bind():
1. 为DOM中的很多元素绑定相同事件; 2. 为DOM中尚不存在的元素绑定事件; 3. 用.bind()的代价是非常大的,它会把相同的一个事件处理程序hook到所有匹配的DOM元素上 4. 不要再用.live()了,它已经不再被推荐了,而且还有许多问题 5. .delegate()会提供很好的方法来提高效率,同时我们可以添加一事件处理方法到动态添加的元素上
我们可以用 .on() 来代替上述的 3 种方法。
不足点也是有的:
1. 并非所有的事件都能冒泡,如load, change, submit, focus, blur 2. 加大管理复杂 3. 不好模拟用户触发事件 4. 如何取舍就看项目实际中运用了
.bind() 绑定事件的时候这些元素必须已经存在,很明显就是直接调用没利用委托机制,如下:
问:单击ddddd,会在最上面显示sdfsdf,但我单击sdfsdf后,并没有显示“on触发”,是因为on不能绑定动态添加的元素吗?
<body>
<p>on,click,delegate</p>
<h2>ddddd</h2>
<span></span
<script>
$("h2").on("click",function(){
$("p:first").before(" <h3>sdfsdf</h3>");
})
$("h3").on("click", function(){
$("span").append("on触发! ");
});
答:on支持动态绑定,只不过需要绑定到父级元素上。(使用委托机制)
<script>
$("h2").on("click",function(){
$("p:first").before(" <h3>sdfsdf</h3>");
})
$("body").on("click","h3", function(){
$("span").append("on触发! ");
});
</script>
jQuery不支持获取隐藏元素的偏移坐标。同样的,也无法取得隐藏元素的 border, margin, 或 padding 信息
cloneNode不会复制javascript属性,比如事件,这个方法只会复制特性。当然IE有这个BUG它会复制事件处理程序。cloneNode(a)方法接受一个布尔值参数,表示是否深拷贝。
true:表示执行深拷贝,复制本节点以及整个子节点树。
false:浅拷贝,只复制节点本身。
复制后返回的节点副本属于文档所有,但是并没有父节点。除非使用 appendChild,insertChild(),replaceChild()将它添加到文档。
cloneNode(true)的时候是遍历的节点,但是不会把对应的事件与数据给复制,但是jQuery.clone方法克隆的时候,是会把该节点上的事件与数据给一并复制过去的,这样的机制是建立在数据分离的基础上。
移除 涉及节点删除的接口jQuery划分了四个分别是detach,empty,remove,unwrap,因为使用的范围不同,所以功能有所差异,但是总的来说都是用来清理节点的。
.empty() 从DOM中移除集合中匹配元素的所有子节点,为了避免内存泄漏,jQuery先移除子元素的数据和事件处理函数,然后移除子元素。
.remove() 将元素移出DOM,当我们想将元素自身移除时我们用 .remove(),同时也会移除元素内部的一切,包括绑定的事件及与该元素相关的jQuery数据。remove是empty的加强版,把本身的父节点也清除掉了。因为remove支持过滤器所以支持传递selecor。remove需要删除自身及其所有的子元素包括事件与数据,所以要通过找到父节点parnetNode移除。
.detach() 如果你想删除元素,不破坏他们的数据或事件处理程序(这些绑定的信息还可以在之后被重新添加回来)。.detach() 方法和.remove()一样, 除了 .detach()保存所有jQuery数据和被移走的元素相关联。当需要移走一个元素,不久又将该元素插入DOM时,这种方法很有用。
innerText是我们常用的文本清理方法,但是火狐下不兼容,不过会提供一个类似的方法叫textContent。
在所有节点类型中,只有DocumentFragment在文档中没有对应的标记。DOM规定文档片段(documentfragment)是一种“轻量级”的文档,可以包含和控制节点,但不会像完整的文档那样占用额外资源。
即当请求把一个 DocumentFragment 节点插入文档树时,插入的不是 DocumentFragment 自身,而是它的所有子孙节点。
jQuery在节点操作上使用了innerHTML,创建效率上来说至少比createElement快了2-10倍不等,而且还能一次性生成一堆的节点,但是随之而来就有一些兼容性问题,
我总结了有以下几点,当然兼容上也结合了jQuery的解决方案。
IE会对用户字符串进行trimLeft操作,用户可能的本意就是需要空白
IE8有些元素innerHTML是只读
IE会忽略开头的无作用域元素
大多情况下不执行script脚本,当然如果支持defer的IE9之前的浏览器除外
一些标签不能作为div的子元素,如tr,tb, col等
jQuery的节点操作最终是需要转化成文档碎片也就是要通过buildFragment()方法处理的,所以innerHTML兼容的修复也自然在buildFragment方法中。
dffkklglg
jjdkdkkdkd
来来来扩扩扩扩
jQuery.each({
parent: function(elem) {
var parent = elem.parentNode;
return parent && parent.nodeType !== 11 ? parent : null;
},
parents: function(elem) {
return dir(elem, "parentNode");
},
parentsUntil: function(elem, until) {
return dir(elem, "parentNode", until);
}
}, function(name, fn) {
ajQuery[name] = function(until, selector) {
return fn(until, selector);
};
});
针对节点的操作有几个重点的细节:
保证最终操作的永远是dom元素,浏览器的最终API只认识那么几个接口,所以如果传递是字符串或者其他的,当然需要转换
针对节点的大量操作,我们肯定是需要引入文档碎片做优化的,这个必不可少
我们知道jQuery的的接口是支持多种参数传递的,那么就需要有一个过滤器的中介来处理各种参数类型。
细节:
1:IE下面innerHTML会忽略没作用域元素,no-scope element(script,link,style,meta,noscript)等,所以这类通过innerHTML创建需要加前缀
2:innerHTML在IE下面会对字符串进行trimLeft操作,去掉空白
3: innerHTML不会执行脚本的代码,如果支持defer除外
4:很多标签不能作为div的子元素、td、tr, tbody等等
5:jQuery是合集对象,文档碎片的与事件的复制问题
针对innerHTML不会执行脚本的代码,如果支持defer除外的解释:
div.innerHTML = "<script>alert(1)</srcript>" 这个代码不会执行
例外的情况:IE9之前满足几个条件
1:script设定defer属性
2: script元素必须位于有作用域元素之后,因为script被认为是无作用域的(页面中不可见)
换句话说,这样设置
div.innerHTML = "<div><script defer>alert(1)</srcript></div>" 可以执行
jQuery在内部通过会有一个domManip方法,把这些问题都方方面面处理掉了
综合上面一系列的问题,jQuery引入了domManip方法
原因清楚了,我们再来看jQuery是如何处理tbody问题,jQuery是兼容IE 6浏览器的。append、prepend、before和after都是操作Dom元素的函数,如果被插入的对象是table,那就要在table中加入tbody标签啊
所以domManip,主要是处理这个问题的,他还处理插入元素的顺序等等
在结构上首先用extend在原型上拓展了一堆方法,其实每一个的实现都很简单,重点就是要看懂domManip的使用。可以重点挑两个方法的实现看一看,不用每个都看。
然后就是appendTo和append之类的处理,大同小异,因为实现差不多,所以就放在一起了
HTML结构:
$('.inner').after('<p>Test</p>');
$对象:
$('.container').after($('h2'));
回调函数
一个返回HTML字符串、DOM 元素、 或者 jQuery 对象的函数,插在每个匹配元素的后面。接收元素在集合中的索引位置作为参数。在函数中this指向元素集合中的当前元素:
.domManip()是jQuery DOM操作的核心函数。dom即Dom元素,Manip是Manipulate的缩写,连在一起就是Dom操作的意思。
对封装的节点操作做了参数上的校正支持,与对应处理的调用:append、prepend、before、after、replaceWith、appendTo、prependTo、insertBefore、insertAfter、replaceAll。
为什么需要用这个domManip函数呢?
我们知道节点操作浏览器提供的接口无非就是那么几个:
appendChild()
通过把一个节点增加到当前节点的childNodes[]组,给文档树增加节点:
cloneNode()
复制当前节点,或者复制当前节点以及它的所有子孙节点:
hasChildNodes()
如果当前节点拥有子节点,则将返回true:
insertBefore()
给文档树插入一个节点,位置在当前节点的指定子节点之前。如果该节点已经存在,则删除之再插入到它的位置:
removeChild()
从文档树中删除并返回指定的子节点:
replaceChild()
从文档树中删除并返回指定的子节点,用另一个节点替换它。
以上接口都有一个特性,传入的是一个节点元素。如果我们传递不是一个dom节点元素,如果是一个字符串,一个函数或者其他呢?
所以针对所有接口的操作,jQuery会抽象出一种参数的处理方案,也就是domManip存在的意义了,针对很多类似接口的参数抽象jQuery内部有很多这样的函数了,如之前属性操作中的jQuery.access。
jQuery children() 方法
获得匹配元素集合中每个元素的子元素,选择器选择性筛选。
因为就jQuery可以是一个DOM的合集对象,所以children
就需要遍历每一个合集中的直接子元素了,并且最后需要构建一个新的jQuery对象。
jQuery find() 方法
1、.find()方法返回被选元素的后代元素,一路向下直到最后一个后代。
2、.find()
方法允许我们能够通过查找DOM树中的这些元素的后代元素,匹配的元素将构造一个新的jQuery对象。
3、.find()
和.children()
方法是相似的,但后者只是再DOM树中向下遍历一个层级。
4、.find()
方法还可以接受一个选择器表达式,该选择器表达式可以是任何可传给$()
函数的选择器表达式。如果紧随兄弟匹配选择器,它将被保留在新构建的jQuery对象中;否则,它被排除在外。
.next() 获得匹配元素集合中每个元素紧邻的同辈元素。.prev() 获得匹配元素集合中每个元素紧邻的前一个同辈元素,由选择器筛选(可选)。.siblings() 获得匹配元素集合中所有元素的同辈元素,由选择器筛选(可选)。
相邻节点的处理是最简单的,在节点上调用nextSibling或者previousSibling,但是我们也要注意相同处理复用的问题:
Siblings的意思就是找到5个li中除去class="third-item"的其余4个,那么我们可以换个思路,可以通过class="third-item"父级ul的第一个子元素开始遍历去筛选,排除class="third-item"即可
function sibling(cur, dir) {
while ((cur = cur[dir]) && cur.nodeType !== 1) {}
return cur;
}
function next(elem) {
return sibling(elem, "nextSibling");
}
function prev(elem) {
return sibling(elem, "previousSibling");
}
通过jQuery能够在DOM树中遍历元素的同胞元素。
其中nextAll、prevAll、nextUntil、prevUntil其实与遍历祖先的的查找处理是非常类似。
.nextAll() 获得匹配元素集合中每个元素之后的所有同辈元素,由选择器进行筛选(可选)。.nextUntil() 获得每个元素之后所有的同辈元素,直到遇到匹配选择器的元素为止。.prevAll() 获得匹配元素集合中每个元素之前的所有同辈元素,由选择器进行筛选(可选)。.prevUntil() 获得每个元素之前所有的同辈元素,直到遇到匹配选择器的元素为止。
alert(item.nextAll()[0].className)
alert(item.prevAll()[0].className)
alert(item.nextUntil('.end')[0].className)
alert(item.prevUntil('.first')[0].className)
同胞就是拥有相同的父元素。
通过jQuery能够在DOM树中遍历元素的同胞元素。
其中nextAll、prevAll、nextUntil、prevUntil其实与遍历祖先的的查找处理是非常类似。
.nextAll() 获得匹配元素集合中每个元素之后的所有同辈元素,由选择器进行筛选(可选)。.nextUntil() 获得每个元素之后所有的同辈元素,直到遇到匹配选择器的元素为止。.prevAll() 获得匹配元素集合中每个元素之前的所有同辈元素,由选择器进行筛选(可选)。.prevUntil() 获得每个元素之前所有的同辈元素,直到遇到匹配选择器的元素为止。
通过 jQuery,能够向上遍历 DOM 树,以查找元素的祖先。
向上遍历 DOM 树,这些 jQuery 方法很有用,它们用于向上遍历 DOM 树:
parent() parents() parentsUntil()
.parent()
方法允许我们能够在DOM树中搜索到这些元素的父级元素,从有序的向上匹配元素,并根据匹配的元素创建一个新的 jQuery 对象。
.parents()
和.parent()
方法是相似的,但后者只是进行了一个单级的DOM树查找
.parentsUntil()
方法会找遍所有这些元素的前辈元素,直到遇到了跟参数匹配的元素才会停止。返回的jQuery对象中包含了所有找到的前辈元素,除了与 .parentsUntil()
选择器匹配的那个元素。
遍历的接口很多都是具有相似或者说是一类的处理功能,那么这种接口的设计我们不能就事论事的一个一个去实现,这样代码就会显得非常累赘也不容易维护,那么就这么几大类Query分了好几十API出来,丰富的接口可以让高层的设计更为简单。但是框架内部的却要简练。那么针对这种类似功能的接口,jQuery内部就会做更多的抽象处理了。
1.针对层级关系的处理,jQuery就抽出了一个dir的方法,用于根据传递的元素与词素的位置关系,查找指定的元素。
parent,parents,parentsUntil等方法如代码所示:
function dir(elem, dir, until) { //参考右边代码 return matched; }
2.我们在上半部的第一章中就提到过迭代器,迭代器是一个框架的重要设计。
我们经常需要提供一种方法顺序的用来处理聚合对象中各个元素,而又不暴露该对象的内部,这也是设计模式中的迭代器模式。
迭代器除了单纯的遍历,在jQuery内部的运用最多的就是接口的抽象合并,相同功能的代码功能合并处理:
jQuery.each({ parent: function(elem) {}, parents: function(elem) {}, nextAll: function(elem) {}, prevAll: function(elem) {}, ................ }, function(name, fn) { api[name] = function(until, selector){ //代码右图 }; });
<div> 元素是 <ul> 的父元素,同时是其中所有内容的祖先。
<ul> 元素是 <li> 元素的父元素,同时是 <div> 的子元素
左边的 <li> 元素是 <span> 的父元素,<ul> 的子元素,同时是 <div> 的后代。
<span> 元素是 <li> 的子元素,同时是 <ul> 和 <div> 的后代。
两个 <li> 元素是同胞(拥有相同的父元素)。
右边的 <li> 元素是 <b> 的父元素,<ul> 的子元素,同时是 <div> 的后代。
<b> 元素是右边的 <li> 的子元素,同时是 <ul> 和 <div> 的后代。
提示:祖先是父、祖父、曾祖父等等。后代是子、孙、曾孙等等。同胞拥有相同的父。
jQuery的遍历处理不仅只是针对基本的层级关系,还扩展了大量的筛选接口,包括了用于筛选、查找和串联元素的方法。之后我们会介绍到各自的实现。
Range dom 接口
createDocumentFragment ; nodeType 11
插入document时, 插入子节点
domManip 抽象
节点操作:
cloneNode,appendNode,hasChildNodes,insertBefore,removeChild
next nextSibling
prev prevSibling