几乎很难从jQuery分离其中的一部分功能。所以在这里我分享下应该读 jQuery 源码的一些成果,以及读源码的方法。啃代码是必须的。
因此必须在支持语法折叠的编辑器里打开源码。 根据折叠层次,我们可以很快知道: 所有 jQuery 的代码都在一个函数中:
<div> <span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">function</span><span style="COLOR: #000000">( window, undefined ) {<br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> jQuery 代码</span><span style="COLOR: #008000"></span><span style="COLOR: #000000"><br><br>})(window);</span> </div>
这样可以避免内部对象污染全局。传入的参数1是 window, 参数2是 undefined , 加快js搜索此二对象的速度。
可以发现 jQuery 代码是按这样顺序来组织:
下面的模块可以用上面的模块,上面的模块不需要下面的模块
总的代码是这样的框架:
<div> <span style="COLOR: #0000ff">var</span><span style="COLOR: #000000"> jQuery </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">function</span><span style="COLOR: #000000">() {<br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 创建 jQuery 对象</span><span style="COLOR: #008000"><br></span><span style="COLOR: #0000ff">var</span><span style="COLOR: #000000"> jQuery </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">function</span><span style="COLOR: #000000">( selector, context ) {<br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 略</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br> };<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 创建 jQuery.fn 对象</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> jQuery.fn </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> jQuery.prototype </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> {<br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 略</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> };<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 声明 jQuery.extend </span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> jQuery.extend </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> jQuery.fn.extend </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">function</span><span style="COLOR: #000000">() {<br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 略</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> };<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 使用 jQuery.extend 扩展自己</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> jQuery.extend({<br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 略</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br> });<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 浏览器方面的一些琐碎</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 略</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 定义全局对象</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> (window.jQuery </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> window.$ </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> jQuery);<br><br>})();</span> </div>
从这里知道: 平时所用的 $ 其实就是 jQuery 函数的别名。
jQuery对象似乎一直都是这东西:
<div> <span style="COLOR: #0000ff">var</span><span style="COLOR: #000000"> jQuery </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">function</span><span style="COLOR: #000000">( selector, context ) {<br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 实际上 jQuery 对象是 jQuery.fn.init 返回的。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> jQuery.fn.init( selector, context, rootjQuery );<br>} </span> </div>
这个函数表示: 要想知道函数 jQuery 是什么东西,必须看 jQuery.fn.init 对象。
同时这也解释了为什么写代码不需要 new jQuery。
再看第29行 - 97行, 都是一些变量声明,这些变量在下面的函数用到。提取变量的好处: 对正则节约编译的时间, 同时能在压缩的时候获得更小的结果。
这个fn 其实是 jQuery.prototype ,这也是为啥jQuery.fn 就是扩展 jQuery对象的唯一原因。
肯能有人会疑问, jQuery 返回 new jQuery.fn.init, 也就是说,平时的函数应该是 jQuery.fn.init.prototype 所有的成员,不是 jQuery.prototype 成员。当然原因也很简单: jQuery.fn.init.prototype === jQuery.prototype (代码 322 行)
jQuery 对js对象处理和中国人讲话一样绕。这里总结下到底 jQuery 对象是个什么家伙。
jQuery 是普通函数, 返回 jQuery.fn.init 对象的实例( new jQuery.fn.init() )。
然后 jQuery.fn === jQuery.prototype === jQuery.fn.init.prototype ,最后, jQuery返回的对象的成员和 jQuery.fn 的成员匹配。
jQuery.fn 下有很多成员,下面稍作介绍:
init - 初始化(下详细说明)
constructor - 手动指定一个构造函数。 因为默认是 jQuery.fn.init
length - 让这个对象更接近一个 原生的数组
size - 返回 length
toArray - 通过 Array.prototype slice 实现生成数组
get - 即 this[ num ] ,当然作了下 参数索引 的处理。
pushStack - 加入一个元素
ready - 浏览器加载后执行(下详细说明)
end - 通过保存的 prevObject 重新返回
each - 参考 http://www.cnblogs.com/Fooo/archive/2011/01/11/1932900.html
参考 http://www.cnblogs.com/rubylouvre/archive/2009/11/21/1607632.html
jQuery.fn.init 就是所谓的 $ 函数。 也就是说,平常的 $("#id") 就是 new jQuery.fn.init("#id");
这个函数很长,但代码覆盖率小。
<div> <span style="COLOR: #000000"> init: </span><span style="COLOR: #0000ff">function</span><span style="COLOR: #000000">( selector, context, rootjQuery ) {<br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 参数: selector 选择器</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> context 上下文</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> rootjQuery 父节点</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 处理 $("")、 $(null) 和 $(undefined)</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">selector ) {<br> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">;<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 处理 $(DOMElement)</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( selector.nodeType ) {<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 直接扔数组中, 就搞定了。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">.context </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> selector;<br> </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">.length </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">;<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 处理 $("body") body 元素只存在一次,单独找它</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( selector </span><span style="COLOR: #000000">===</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">body</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">context </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> document.body ) {<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 同样扔数组中, 顺便把 selector 更新更新。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">.context </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> document;<br> </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> document.body;<br> thisis.selector </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">body</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br> </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">.length </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">;<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 处理 $(HTML 代码 或者是 css 选择器) </span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( </span><span style="COLOR: #0000ff">typeof</span><span style="COLOR: #000000"> selector </span><span style="COLOR: #000000">===</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">string</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> ) {<br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 略</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> <br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 处理 $(函数)</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> } </span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( jQuery.isFunction( selector ) ) {<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 如果是函数,则执行 $(document).ready , 这样 $(document).ready(func) 简为 $(func)</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> rootjQuery.ready( selector );<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 略。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 如果传入的是一个 Dom列表 ( getElementsByTagName 结果 ) 则转为 jQuery 数组。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> jQuery.makeArray( selector, </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000"> );<br>}</span> </div>
<div> <span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 这部分代码是 上段中 略 的 也就是说是 jQuery(字符串) 处理。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 检查是否字符串是常用选择器 (/^(?:[^)[^>]*$|#([\w\-]+)$)/)</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">match </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> quickExpr.exec( selector );<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 检查是否正确匹配</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( match </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> (match[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">] </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">context) ) {<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 处理: $(html) -> $(array)</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( match[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">] ) {<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 获取正文,默认 document</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> context </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> context </span><span style="COLOR: #0000ff">instanceof</span><span style="COLOR: #000000"> jQuery </span><span style="COLOR: #000000">?</span><span style="COLOR: #000000"> context[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">] : context;<br> doc </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> (context </span><span style="COLOR: #000000">?</span><span style="COLOR: #000000"> context.ownerDocument </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> context : document);<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 如果传入简单的 "", ( /^(?:)?$/)</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> ret </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> rsingleTag.exec( selector );<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 返回 createElement("tag")</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> jQuery.merge( </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">, selector );<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 处理: $("#id")</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> } </span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"> {<br> elem </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> document.getElementById( match[</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">] );<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 因为有的浏览器 getElementById 不只返回 id匹配的,所以做检查。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">;<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 处理 $("标签")</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> } </span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">context </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">rnonword.test( selector ) ) {<br> </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">.selector </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> selector;<br> </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">.context </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> document;<br> selector </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> document.getElementsByTagName( selector );<br> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> jQuery.merge( </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">, selector );<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">处理: $(选择器, $(...))</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> } </span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">context </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> context.jquery ) {<br> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> (context </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> rootjQuery).find( selector );<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 处理: $(选择器, 上下文)</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> (相当于: $(上下文).find(选择器)</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> } </span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"> {<br> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">.constructor( context ).find( selector );<br> }</span> </div>
这个函数用于 扩展函数
函数中含多个参数判断,为了使用可以更灵活。
基本原理就是for(in),这里不具体介绍了。
<div> <span style="COLOR: #000000">noConflict: </span><span style="COLOR: #0000ff">function</span><span style="COLOR: #000000">( deep ) {<br> window.$ </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> _$;<br><br> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( deep ) {<br> window.jQuery </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> _jQuery;<br> }<br><br> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> jQuery;<br> },</span> </div>
不多解释了,就是让 jQuery 恢复为全局的对象。
其中有2个函数:
jQuery.ready 触发执行 readyList 中的所有函数
jQuery.bindReady 初始化让 jQuery.ready 成功执行
<div> <span style="COLOR: #000000">bindReady: </span><span style="COLOR: #0000ff">function</span><span style="COLOR: #000000">() {<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 如果已经执行 bindReady 则返回。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( readyBound ) {<br> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">;<br> }<br><br> readyBound </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 如果页面已经加载, 马上执行 jQuery.ready</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( document.readyState </span><span style="COLOR: #000000">===</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">complete</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> ) {<br> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> setTimeout( jQuery.ready, </span><span style="COLOR: #000000">1</span><span style="COLOR: #000000"> );<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 标准浏览器支持 DOMContentLoaded</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( document.addEventListener ) {<br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 你懂的</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> document.addEventListener( </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">DOMContentLoaded</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">, DOMContentLoaded, </span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000"> );<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 为什么还要 load ? , 因为有些时候 DOMContentLoaded 失败(如 iframe) ,而 load 总是会成功, 所以,同时处理 DOMContentLoaded load, 在 jQuery.ready 中会删除监听函数,保证最后这个函数只执行一次</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> window.addEventListener( </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">load</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">, jQuery.ready, </span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000"> );<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> IE浏览器( IE 8 以下)</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> } </span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( document.attachEvent ) {<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 使用 onreadystatechange</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> document.attachEvent(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">onreadystatechange</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">, DOMContentLoaded);<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 同理</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> window.attachEvent( </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">onload</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">, jQuery.ready );<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 如果 IE 下且非 iframe, 这里有个技巧。 见 doScrollCheck();</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 原理: 浏览器在没加载时 设置 scrollLeft 会错误,所哟每隔1秒厕所 是否 scrollLeft 成功,如果发现成功,则执行 jQuery.ready 。但这只对非 frame 会有用。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">var</span><span style="COLOR: #000000"> toplevel </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">;<br><br> </span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000"> {<br> toplevel </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> window.frameElement </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">null</span><span style="COLOR: #000000">;<br> } </span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000">(e) {}<br><br> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( document.documentElement.doScroll </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> toplevel ) {<br> doScrollCheck();<br> }<br> }<br> },</span> </div>
bindReady 函数在执行 ready 时执行。(jQuery 1.4 之前版本都是 绝对执行,不管需不需要 ready 函数)
人人都说 jQuery.support 是个好东西。确实,这东西可以解决很多兼容问题。
jQuery.support 是基于检测的浏览器兼容方式。也就是说,创建一个元素, 看这个元素是否符合一些要求。
比如测试元素是否支持checkOn属性,只要先 set check = 'on' 然后看浏览器是否 get check == 'on'。
此部分源码不具体介绍了。
jQuery的 data() 用于存储一个字典。而这些数据最后都保存在 jQuery.cache ( 代码 1283 行) , 全局对象存在 windowData ( 代码 1279 行) 。
但如果正确根据对象找到其在 jQuery.cache 的存储对象? 这就是 expando 字符串。
比如一个对象: elem 。
满足: elem.expando = "jQuery12321";
那么 jQuery.cache["jQuery12321"] 就是存储这个 elem 数据的对象。
实际上, 不是 elem.expando 表示键值,而是 elem[ jQuery.expando ] 表示。
而一个对象数据又是一个字典,所以最后执行 jQuery.data(elem, 'events') 后就是:
jQuery.cache[elem[jQuery.expando]]['events'] 的内容 (jQuery.cache[elem[jQuery.expando]] = {} )
队列是 jQuery 1.5 新增的。
主要用于特效等需要等待执行的时候。
队列主要操作就是 进队queue 出队dequeue
jQuery 队列内的数据:
如果没有执行:
[将执行的1, 将执行的2]
现在开始执行 , 如果 type 为空或 "fx", 队列内数据:
["inprogress", 将执行的2]
执行完之后:
["将执行的2]
以上的这些数据都存在 jQuery.data(obj, (type || "fx") + "queue") (代码 1520 - 1522行)
jQuery.delay 则用于延时执行一个函数。相当于把原来队列更新为 setTImeout 后的结果。 (代码 1589 -1598 行)
从这里开始,需要了解一个函数jQuery.access。对于 attr ,css 之类的函数,如果需要返回值,只返回第一个元素的值,如果是设置值,则设置每个元素的值。这个神奇的效果就是 jQuery.access 搞定的。
jQuery.access代码在 794 - 819 行
jQuery大部分函数都是依赖 jQuery.access 实现的,比如有一个函数 XX,对用户而言,调用的是 jQuery.fn.XX, 而这个函数需要对多个元素(jQuery数组内的所有的节点) 操作,或者对1个元素操作, 通过 jQuery.access 转换(不一定都是),最后只写对1个元素的操作。这1个元素的操作往往是 jQuery.XX 函数,因此,我们往往能看到即存在 jQuery.XX, 又存在 jQuery.fn.XX, 而其实 jQuery.fn.XX 都是依靠 jQuery.XX 的,或者说jQuery.XX是底层函数, jQuery.fn.XX 是方便用户的工具 。
jQuery.fn.attr 这个函数(代码 1632 - 1634 行) 只有1句话,真正的实现是 jQuery.attr (代码 1880 - 1988)
又是一个大于100行的函数
<div> <span style="COLOR: #000000">attr: </span><span style="COLOR: #0000ff">function</span><span style="COLOR: #000000">( elem, name, value, pass ) {<br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 检查是否为 nodeType 为 Element</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">elem </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> elem.nodeType </span><span style="COLOR: #000000">===</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">3</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> elem.nodeType </span><span style="COLOR: #000000">===</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">8</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> elem.nodeType </span><span style="COLOR: #000000">===</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">2</span><span style="COLOR: #000000"> ) {<br> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> undefined;<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 如果这个属性需要特殊对待。 height/width/left 等属性需特殊计算</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( pass </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> name </span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000"> jQuery.attrFn ) {<br> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> jQuery(elem)[name](value);<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 检查是否为 XML 还 HTML </span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">var</span><span style="COLOR: #000000"> notxml </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> elem.nodeType </span><span style="COLOR: #000000">!==</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">1</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">jQuery.isXMLDoc( elem ),<br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> Whether we are setting (or getting)</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> set </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> value </span><span style="COLOR: #000000">!==</span><span style="COLOR: #000000"> undefined;<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 修正名字, 比如 float 改 cssFloat</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> name </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> notxml </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> jQuery.props[ name ] </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> name;<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 只有在节点的时候执行。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( elem.nodeType </span><span style="COLOR: #000000">===</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">1</span><span style="COLOR: #000000"> ) {<br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 在 IE7- 下, href src 属性直接获取会返回绝对位置,而不是真实的位置字符串,</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 要获得它们的真实值,需要 elem.getAttribute("href", 2);</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">var</span><span style="COLOR: #000000"> special </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> rspecialurl.test( name );<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> Safari 误报默认选项。通过获取父元素的已选择索引来修复。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( name </span><span style="COLOR: #000000">===</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">selected</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">jQuery.support.optSelected ) {<br> </span><span style="COLOR: #0000ff">var</span><span style="COLOR: #000000"> parent </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> elem.parentNode;<br> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( parent ) {<br> parent.selectedIndex;<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 对 optgroups ,同理</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( parent.parentNode ) {<br> parent.parentNode.selectedIndex;<br> }<br> }<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 检查属性是否存在, 有些时候 name in elem 会失败,所以多次测试。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( (name </span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000"> elem </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> elem[ name ] </span><span style="COLOR: #000000">!==</span><span style="COLOR: #000000"> undefined) </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> notxml </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">special ) {<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 如果设置属性</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( set ) {<br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 在IE, 不能设置属性 type 。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( name </span><span style="COLOR: #000000">===</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">type</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> rtype.test( elem.nodeName ) </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> elem.parentNode ) {<br> jQuery.error( </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">type property can't be changed</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> );<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 如果 value === null, 表示移除属性</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( value </span><span style="COLOR: #000000">===</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">null</span><span style="COLOR: #000000"> ) {<br> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( elem.nodeType </span><span style="COLOR: #000000">===</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">1</span><span style="COLOR: #000000"> ) {<br> elem.removeAttribute( name );<br> }<br><br> } </span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"> {<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 一切属性设置就是1句话。。。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> elem[ name ] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> value;<br> }<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 表单索引元素获取需要 getAttributeNode( name ).nodeValue</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( jQuery.nodeName( elem, </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">form</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> ) </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> elem.getAttributeNode(name) ) {<br> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> elem.getAttributeNode( name ).nodeValue;<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> elem.tabIndex 特殊处理</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( name </span><span style="COLOR: #000000">===</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">tabIndex</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> ) {<br> </span><span style="COLOR: #0000ff">var</span><span style="COLOR: #000000"> attributeNode </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> elem.getAttributeNode( </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">tabIndex</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> );<br><br> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> attributeNode </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> attributeNode.specified </span><span style="COLOR: #000000">?</span><span style="COLOR: #000000"><br> attributeNode.value :<br> rfocusable.test( elem.nodeName ) </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> rclickable.test( elem.nodeName ) </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> elem.href </span><span style="COLOR: #000000">?</span><span style="COLOR: #000000"><br> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> :<br> undefined;<br> }<br><br> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> elem[ name ];<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 处理 style 属性</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">jQuery.support.style </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> notxml </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> name </span><span style="COLOR: #000000">===</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">style</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> ) {<br> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( set ) {<br> elem.style.cssText </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">""</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> value;<br> }<br><br> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> elem.style.cssText;<br> }<br><br> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( set ) {<br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 这里除了 IE, 其它属性使用标准 setAttribute </span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> elem.setAttribute( name, </span><span style="COLOR: #000000">""</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> value );<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 如果属性不存在,返回 undefined, 而不是 null 或 "" 之类的。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">elem.attributes[ name ] </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> (elem.hasAttribute </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">elem.hasAttribute( name )) ) {<br> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> undefined;<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 见上</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">var</span><span style="COLOR: #000000"> attr </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">jQuery.support.hrefNormalized </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> notxml </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> special </span><span style="COLOR: #000000">?</span><span style="COLOR: #000000"><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> Some attributes require a special call on IE</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> elem.getAttribute( name, </span><span style="COLOR: #000000">2</span><span style="COLOR: #000000"> ) :<br> elem.getAttribute( name );<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 同上</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> attr </span><span style="COLOR: #000000">===</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">null</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">?</span><span style="COLOR: #000000"> undefined : attr;<br> }<br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 如果不是 DOM 元素,检查处理。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( set ) {<br> elem[ name ] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> value;<br> }<br> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> elem[ name ];<br> }</span> </div>
平时我们都是调用 click(func) 之类的函数, 而其实这些都是工具函数,真正和事件挂钩的函数是
jQuery.fn.bind - 调用 jQuery.event.add
jQuery.fn.unbind - 调用 jQuery.event.remove
jQuery.fn.trigger - 调用 jQuery.event.trigger
jQuery.fn.one - 调用 jQuery.fn.bind,Query.fn.unbind
要想知道jQuery的事件原理,必须读 jQuery.event.add (代码 2012 - 2155 行)
<div> <span style="COLOR: #000000">add: </span><span style="COLOR: #0000ff">function</span><span style="COLOR: #000000">( elem, types, handler, data ) {<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 只对节点操作。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( elem.nodeType </span><span style="COLOR: #000000">===</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">3</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> elem.nodeType </span><span style="COLOR: #000000">===</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">8</span><span style="COLOR: #000000"> ) {<br> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">;<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> IE 无法传递 window,而是复制这个对象 。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( jQuery.isWindow( elem ) </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> ( elem </span><span style="COLOR: #000000">!==</span><span style="COLOR: #000000"> window </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">elem.frameElement ) ) {<br> elem </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> window;<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 如果 handler === false, 也就是说就是阻止某事件,</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 这样只要 bind("evt", false); 就是阻止此事件。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( handler </span><span style="COLOR: #000000">===</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000"> ) {<br> handler </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> returnFalse;<br> } </span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">handler ) {<br> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">;<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> handleObjIn 是内部处理句柄, handleObj 是直接使用的处理句柄。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">var</span><span style="COLOR: #000000"> handleObjIn, handleObj;<br><br> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( handler.handler ) {<br> handleObjIn </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> handler;<br> handler </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> handleObjIn.handler;<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 为函数生成唯一的 guid 。具体下面介绍。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">handler.guid ) {<br> handler.guid </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> jQuery.guid</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">;<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 获取一个节点的数据。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">var</span><span style="COLOR: #000000"> elemData </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> jQuery.data( elem );<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 如果没有数据,则直接返回。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">elemData ) {<br> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">;<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 避免和原生的js对象混淆。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">var</span><span style="COLOR: #000000"> eventKey </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> elem.nodeType </span><span style="COLOR: #000000">?</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">events</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> : </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">__events__</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 这里就是关键。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> elemData 是存储数据的位置, 而 elemData[ eventKey ] 就是存储当前事件的对象。 elemData.handle 就是当前绑定的所有函数数组。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 也就是说,当我们绑定一个函数时,会往 elemData.handle 放这个函数,然后事件触发时,会遍历 elemData.handle 中函数然后去执行。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 肯能有人会问,为什么这么做,因为原生的DOM内部也有一个 函数数组,事件触发后会执行全部函数。答案还是 兼容。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 标准浏览器使用 addEventListener</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> IE 使用 attachEvent</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 而这2者还是有差距的。因为 addEventListener 执行函数的顺序即添加函数的顺序,然而 attachEvent 执行函数的顺序和添加的顺序是相反的。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> jQuery 使用自定义的 handler 数组,好处有:</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 因为最后仅绑定一次原生事件,事件触发后,手动执行 数组中的函数。这样保证兼容。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 同时也可以知道到底绑定了什么函数,可以方便 trigger 函数的完成。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br> events </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> elemData[ eventKey ],<br> eventHandle </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> elemData.handle;<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 一些功能。。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( </span><span style="COLOR: #0000ff">typeof</span><span style="COLOR: #000000"> events </span><span style="COLOR: #000000">===</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">function</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> ) {<br> eventHandle </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> events.handle;<br> events </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> events.events;<br><br> } </span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">events ) {<br> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">elem.nodeType ) { <br> elemData[ eventKey ] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> elemData </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">function</span><span style="COLOR: #000000">(){};<br> }<br><br> elemData.events </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> events </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> {};<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 如果是第一次执行,需创建 eventHandle</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">eventHandle ) {<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> eventHandle 就是真正绑定到原生事件的那个函数,这个函数用来执行events.hadlers 用。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> elemData.handle </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> eventHandle </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">function</span><span style="COLOR: #000000">() {<br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> Handle the second event of a trigger and when</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> an event is called after a page has unloaded</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">typeof</span><span style="COLOR: #000000"> jQuery </span><span style="COLOR: #000000">!==</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">undefined</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">&&</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">jQuery.event.triggered </span><span style="COLOR: #000000">?</span><span style="COLOR: #000000"><br> jQuery.event.handle.apply( eventHandle.elem, arguments ) :<br> undefined;<br> };<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 绑定函数和原生,这样可以保证函数可执行为目前作用域。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> eventHandle.elem </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> elem;<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 处理 jQuery(...).bind("mouseover mouseout", fn);</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> types </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> types.split(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><br> </span><span style="COLOR: #0000ff">var</span><span style="COLOR: #000000"> type, i </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">, namespaces;<br><br> </span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000"> ( (type </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> types[ i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000"> ]) ) {<br> handleObj </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> handleObjIn </span><span style="COLOR: #000000">?</span><span style="COLOR: #000000"><br> jQuery.extend({}, handleObjIn) :<br> { handler: handler, data: data };<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 略</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> <br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 绑定 type guid</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> handleObj.type </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> type;<br> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">handleObj.guid ) {<br> handleObj.guid </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> handler.guid;<br> }<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 获取当前的函数数组。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">var</span><span style="COLOR: #000000"> handlers </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> events[ type ],<br> special </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> jQuery.event.special[ type ] </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> {};<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 如果第一次,则创建这个数组。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">handlers ) {<br> handlers </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> events[ type ] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> [];<br><br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 特殊事件要执行 setup 而不是标准 addEventListener。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 此行用来支持自定义的事件。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">special.setup </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> special.setup.call( elem, data, namespaces, eventHandle ) </span><span style="COLOR: #000000">===</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000"> ) {<br> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 标准事件。 这里绑定的为 eventHandle</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( elem.addEventListener ) {<br> elem.addEventListener( type, eventHandle, </span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000"> );<br><br> } </span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( elem.attachEvent ) {<br> elem.attachEvent( </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">on</span><span style="COLOR: #000000">"</span><s></s> </div>