<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>jljlpch</title>
    <description></description>
    <link>http://jljlpch.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>mootools 1.1.1extend的功能测试</title>
        <author>jljlpch</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jljlpch.javaeye.com">jljlpch</a>&nbsp;
          链接：<a href="http://jljlpch.javaeye.com/blog/235622" style="color:red;">http://jljlpch.javaeye.com/blog/235622</a>&nbsp;
          发表时间: 2008年09月02日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="html"></pre>
<pre name="code" class="html">prk</pre>
<pre name="code" class="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&gt;
&lt;html&gt;
	&lt;head&gt;		
		&lt;script type="text/javascript" src="javascript/mootools.js"&gt;&lt;/script&gt;
		&lt;title&gt;&lt;/title&gt;
		&lt;script type="text/javascript"&gt;
      var Animal = new Class({			
			getAge:function(){alert("this is the first Parent.");}
		});
		var Cat = Animal.extend({
			getAge:function(){
			this.parent();
		    alert("this is the second Parent.");
			}
		});
		var homeCat=Cat.extend({
			getAge:function(){			
		    alert("this is the third Parent.");
			this.parent();
			}
			});	
		var myCat = new homeCat();
			myCat.getAge();
		
       &lt;/script&gt;
		
	&lt;/head&gt;

	&lt;body&gt;

	&lt;/body&gt;


&lt;/html&gt;</pre>
<p>&nbsp;</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://jljlpch.javaeye.com/blog/235622#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 02 Sep 2008 10:51:26 +0800</pubDate>
        <link>http://jljlpch.javaeye.com/blog/235622</link>
        <guid>http://jljlpch.javaeye.com/blog/235622</guid>
      </item>
      <item>
        <title>T-SQL 存储过程</title>
        <author>jljlpch</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jljlpch.javaeye.com">jljlpch</a>&nbsp;
          链接：<a href="http://jljlpch.javaeye.com/blog/235550" style="color:red;">http://jljlpch.javaeye.com/blog/235550</a>&nbsp;
          发表时间: 2008年09月02日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>prk/彭仁夔&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;08-09-02&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 转载注明出处。</p>
<p>在开发中，我们经常要用到这样的统计</p>
<p>&nbsp;</p>
<p>根据用户输入的日期，把每个月的备份表的数据和正在使用的表中的综合起来统计。假如2008-05-11到2008-08-01，那么就包含5，6，7，8四张备份表还有正在使用的表，加起5张表。这是要统计的所有的数据。</p>
<p>&nbsp;</p>
<p>对于统计又有要求，分情况来统计各种情况的总计，但是有的特殊情况要统计其明细。</p>
<p>如下图：</p>
<p>&nbsp;T-sql日期转换不兼容。还有对运行的sql的长度也有一定的限制。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>prk/彭仁夔&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;08-09-02&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 转载注明出处。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<pre name="code" class="sql">
ALTER PROCEDURE [dbo].[UP_TSMReceivedDailyReport]
@StartTime varchar(100),
@EndTime    varchar(100),
@OrgAddrs  varchar(1000)='',
@MsgType_IDs  varchar(1000)=''
 AS 
     declare @where  varchar(1000)
     declare @startMonth  int 
     declare @endMonth int 
     declare @tempMonth int
     declare @generalSql varchar(1000)
     declare @tempSql varchar(1000)
     declare @tempSql1 varchar(3000)
     declare @tempTotal varchar(3000)
     declare @tempUndeal varchar(3000)
     declare @tempdealing varchar(3000)
     declare @tempdealed varchar(3000)
     declare @temp1 varchar(3000)
     declare @temp2 varchar(3000)
     declare @temp3 varchar(3000)
     declare @temp4 varchar(3000)
     declare @mm int
     declare @mm1 int
  /*
    declare @StartTime varchar(100)
    declare @EndTime    varchar(100)
    declare @OrgAddrs  varchar(1000)
    declare @MsgType_IDs  varchar(1000)
 
   set @StartTime ='2008-05-05'
   set  @EndTime  ='2008-07-07'
   set  @OrgAddrs =''
   set  @MsgType_IDs =''
*/
    set  @startMonth=Month(@StartTime)
    set  @endMonth =Month(@EndTime)
    set  @tempMonth=@startMonth
    set  @tempSql=' '
    set  @tempSql1=' '
    set  @temp1=' '
    set  @temp2=' '
    set  @temp3=' '
    set  @temp4=' '
    set  @where=' where recvTime&gt;='''+CAST(@StartTime as varchar(20))+''' and recvTime&lt;='''+CAST(@EndTime as varchar(20))+'''  '

    if @OrgAddrs!=''
     begin
      set @where=@where+' '+ ' and OrgAddr in '+@OrgAddrs+' '
      end
    
    if @MsgType_IDs!=''
       begin
       set @where=@where+' '+ ' and MsgType_ID in '+@MsgType_IDs+' '
       end
     print @where
     set @generalSql=' select RecvSM_ID,User_ID,MsgType_ID,OrgAddr ,DestAddr, cast(RecvTime as DateTime) RecvTime,
       SM_Content,DealSign,cast(DealTime as DateTime) DealTime,IsWait,ReMsgType_ID,SendSM_Content   
         from T_SMReceived '+@where+' and DealSign&lt;&gt;4  and (DealSign&lt;&gt;8 and iswait&lt;&gt;0) and (DealSign&lt;&gt;3 and IsWait&lt;&gt;0)'
       print @generalSql

create table #temp  (RecvSM_ID int, 
                      User_ID int, 
                      MsgType_ID int, 
                     OrgAddr varchar(128), 
                     DestAddr varchar(128), 
                     RecvTime datetime, 
                     SM_Content varchar(6000), 
                     DealSign tinyint, 
                     DealTime datetime,
                     IsWait bit, 
                     ReMsgType_ID int ,
                     SendSM_Content varchar(6000) )
   
    insert into #temp exec (@generalSql)
  
while @tempMonth&lt;=@endMonth
       begin      
   set @tempSql='select RecvSM_ID,User_ID,MsgType_ID,OrgAddr ,DestAddr, cast(RecvTime as DateTime) RecvTime,
       SM_Content,DealSign,cast(DealTime as DateTime) DealTime,IsWait,ReMsgType_ID,SendSM_Content   from T_SMReceived_'+Cast(@tempMonth as varchar(2))+'  '+@where+' '
     insert into #temp  exec (@tempSql)       
       
     set @tempMonth= @tempMonth+1
     end   
     
      select @mm= count(*) from #temp
    print 'the temp table have:'+cast(@mm as varchar(100))

     set @temp1='select  msgtype_id  ,convert(varchar(10),recvtime,120) recvtime , total=count(*)     from #temp  '
     set @temp2=' group by  convert(varchar(10),recvtime,120), msgtype_id  '
     set @tempTotal = @temp1+''+@temp2
     print @tempTotal
     set @tempUndeal = @temp1+' where (iswait=1 and DealSign=0) or DealSign=2  or (iswait=1 and DealSign=8) '+@temp2
     print @tempUndeal
     set @tempdealing =@temp1+' where (iswait=1 and DealSign=1) or (iswait=1 and DealSign=9) '+@temp2
     print @tempdealing
     set @tempdealed =@temp1+' where (iswait=0 and DealSign=3) or (iswait=0 and DealSign=4) '+@temp2
     print @tempdealed

     set @temp3='select a.MsgType_ID , a.RecvTime,a.total,
     (select undeal= case  when b.total IS NULL  then 0 else b.total end) undeal ,
     (select dealing= case  when c.total IS NULL  then 0 else c.total end) dealing,
     (select dealed= case  when d.total IS NULL  then 0 else d.total end) dealed,
      undealDetail=null,dealingDetail=null,dealedDetail=null from ('+@tempTotal+') a left join ('
        +@tempUndeal+') b on a.msgtype_id=b.msgtype_id and a.recvtime=b.recvtime left join ('+
        @tempdealing+' ) c on a.msgtype_id=c.msgtype_id and a.recvtime=c.recvtime left join ( '
        +@tempdealed+') d on a.msgtype_id=d.msgtype_id and a.recvtime=d.recvtime'
    
   print '#temp1 SQL: '+ @temp3

create table #temp1  (
                     MsgType_ID int,                      
                     RecvTime varchar(10), 
                     total int,
                     undeal int,                      
                     dealing int,                     
                     dealed int,
                     undealDetail varchar(1000),
                     dealingDetail varchar(1000),
                     dealedDetail varchar(1000),                    
                     ) 

 insert into #temp1   exec(@temp3)


      select @mm1= count(*) from #temp1
print 'the #templ have :'+cast(@mm1 as varchar(100))

declare finalReport cursor 
  for select MsgType_ID,convert(varchar(10),recvtime,120) RecvTime ,dealed from #temp1
   open finalReport

     declare @MsgType_IDf int
     declare @RecvTimef varchar(10)
     declare @dealedf int
      print  'start tatal one record';
     fetch next from finalReport into @MsgType_IDf, @RecvTimef ,@dealedf
      while(@@fetch_status=0)
         begin

             declare my_cursor cursor 
              
              for  select a.msgtype_id ,a.recvtime,a.size,a.reMsgType_ID,b.ReMsgTypeName from
                     (select msgtype_id,count(*) size, convert(varchar(10),recvtime,120) recvtime,reMsgType_ID from #temp 
                       where convert(varchar(10),recvtime,120)=@RecvTimef and msgtype_id=@MsgType_IDf and (iswait=0 and (DealSign=3 or DealSign=4))   group by  convert(varchar(10),recvtime,120), msgtype_id,reMsgType_ID) a left join T_ReMsgType b
                      on a.reMsgType_ID=b.reMsgType_ID order by a.msgtype_id

                open my_cursor

                 declare @msgtype_id int
                 declare @recvtime varchar(10)
                 declare @reMsgType_ID int
                 declare @ReMsgTypeName varchar(500)
                 declare @dealedDetail varchar(500)
                 declare @size int
                 declare @flag int

                 set @flag=0
                 set @dealedDetail='总数:'+Cast(@dealedf as varchar(5))+' (其中 '
                  print  'start deal one record';
               fetch next from my_cursor into @msgtype_id,@recvtime,@size,@reMsgType_ID,@ReMsgTypeName
                 while(@@fetch_status=0)
                       begin

                         set @dealedDetail= @dealedDetail+@ReMsgTypeName+': '+                 
                         Cast((select undeal= case  when @size IS NULL  then 0  else @size end) as varchar(5))+','
                          set @flag=1  
                  
                         fetch next from my_cursor into @msgtype_id,@recvtime,@size,@reMsgType_ID,@ReMsgTypeName
                       end

                   if @flag=0
                       begin
                       set @dealedDetail=substring(@dealedDetail,0,len(@dealedDetail)-3)
                       end
                    else 
                       begin
                         set @dealedDetail=substring(@dealedDetail,0,len(@dealedDetail))+')'
                       end
                close my_cursor 
                DEALLOCATE my_cursor
          update #temp1 set dealedDetail= @dealedDetail  where convert(varchar(10),recvtime,120)=@RecvTimef and msgtype_id=@MsgType_IDf 
            print  'have update one record';

     fetch next from finalReport into @MsgType_IDf, @RecvTimef ,@dealedf
          end
    close finalReport
    DEALLOCATE finalReport

 select c.*,d.MsgTypeName from #temp1 c left join T_MsgType d on c.msgtype_id=D.msgtype_id  order by c.RecvTime,c.msgtype_id
</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://jljlpch.javaeye.com/blog/235550#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 02 Sep 2008 08:02:44 +0800</pubDate>
        <link>http://jljlpch.javaeye.com/blog/235550</link>
        <guid>http://jljlpch.javaeye.com/blog/235550</guid>
      </item>
      <item>
        <title>Jquery1.2.6 源码分析</title>
        <author>jljlpch</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jljlpch.javaeye.com">jljlpch</a>&nbsp;
          链接：<a href="http://jljlpch.javaeye.com/blog/234218" style="color:red;">http://jljlpch.javaeye.com/blog/234218</a>&nbsp;
          发表时间: 2008年08月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 24pt; line-height: 20pt; mso-char-indent-count: 2.0; mso-line-height-rule: exactly;"><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">jQuery</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">是一个非常优秀的</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">JS</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">库，与</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">Prototype,YUI,Mootools</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">等众多的</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">Js</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">类库相比，它剑走偏锋，从</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">web</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">开发的实用角度出发，抛除了其它</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">Lib</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">中一些中看但不实用的东西，为开发者提供了优美短小而精悍的类库。其使用简单，文档丰富，而且性能高效，能极大地提高</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">web</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">系统的开发效率。因此可以说是</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">web</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">应用开发中最佳的</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">Js</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">辅助类库之一。大部分开发者正在抛弃</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">Prototype</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">，而选择</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">Jquery</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">做为他们进行</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">web</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">开发的</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">JS</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">库。</span><span lang="EN-US" style="font-size: 12pt;"></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 24pt; line-height: 20pt; mso-char-indent-count: 2.0; mso-line-height-rule: exactly;"><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">如是开发人员仅仅只知道文档中的简单的使用方法，却不明白</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">Jquery</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">的运行原理和内部机制，在使用</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">jquery</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">时，肯定会碰到许多的问题。这些问题有一部分是</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">Jquery</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">的</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">Bug</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">。大部分是自身的使用不当而造成的。而文档的简单的使用说明很难解决问题。在调试基于</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">jQuery</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">的</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">web</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">应用时，很多时候都要跟踪进入</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">jQuery</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">对象分析其运行状态以了解出错的原因。</span><span lang="EN-US" style="font-size: 12pt;"></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 24pt; line-height: 20pt; mso-char-indent-count: 2.0; mso-line-height-rule: exactly;"><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">如果对于</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">web</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">的应用的页面运行性能和效率有所要求的话，那么我们更应该去明白其运行机理和核心源码。但是</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">jQuery</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">源码不像其它的类库那样，它有点晦涩，难懂。这就是本源码分析的原因，让所有使用</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">jQuery</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">的读者，能快速上手</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">jQuery</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">的源码，并在开发中得心应用。</span><span lang="EN-US" style="font-size: 12pt;"></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 24pt; line-height: 20pt; mso-char-indent-count: 2.0; mso-line-height-rule: exactly;"><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">Jquery</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">的网络资源丰富，但</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">Baidu</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">了很久，很难找到那种完全深入地分析</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">Jquery</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">源码的文稿。倒是</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">Jquery</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">的开发者，</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">John Resi</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">的《</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">Pro Javascript Techniques</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">》涉及到</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">Jquery</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">的源码的分析，但是其主指还是在于</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">JavaScript</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">的使用。那本书并不能使我们完全细致地了解</span><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: Times New Roman;">Jquery</span></span><span style="font-size: 12pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">的源码。</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 24pt; line-height: 20pt; mso-char-indent-count: 2.0; mso-line-height-rule: exactly;">&nbsp;</p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 24pt; line-height: 20pt; mso-char-indent-count: 2.0; mso-line-height-rule: exactly;"><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: 宋体;">写个这个源码分析的理由其实很简单，在工作中使用jquery经常出问题，不得不分析其源码，我把分析的源码放在blog。其标题是jquery core 源码分析。结果有一网友竟评论说打到标题党，可见还是有很多人像我这样想完全了解jquery的core代码。</span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 24pt; line-height: 20pt; mso-char-indent-count: 2.0; mso-line-height-rule: exactly;"><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: 宋体;">从自己能看懂，到自己写出来。发现自己有一个质的提高。但是由于水平有限，分析过程的难免有错误。请大家多多指教。不过嘴下能留情就最好了。有什么问题可以到blog:jljlpch.javaeye.com去访问和评论。附件附有打包的源码。</span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 24pt; line-height: 20pt; mso-char-indent-count: 2.0; mso-line-height-rule: exactly;"><span lang="EN-US" style="font-size: 12pt;"><span style="font-family: 宋体;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2008-08-29&nbsp;&nbsp; prk</span></span></p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://jljlpch.javaeye.com/blog/234218#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 29 Aug 2008 00:13:37 +0800</pubDate>
        <link>http://jljlpch.javaeye.com/blog/234218</link>
        <guid>http://jljlpch.javaeye.com/blog/234218</guid>
      </item>
      <item>
        <title>jquery fx分析</title>
        <author>jljlpch</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jljlpch.javaeye.com">jljlpch</a>&nbsp;
          链接：<a href="http://jljlpch.javaeye.com/blog/234130" style="color:red;">http://jljlpch.javaeye.com/blog/234130</a>&nbsp;
          发表时间: 2008年08月28日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">8 FX分析</pre>
<pre name="code" class="java">              prk/彭仁夔            转载请注明出处  <a href="http://jljlpch.javaeye.com/">http://jljlpch.javaeye.com/</a>
8.1 FX的常用方法
和前面分析的代码相比，FX是非常让人兴奋的。以前javaeye登陆的时候，对其登陆窗口的淡出淡入的特效总是想入非非。Jquery的core包中也提供了Fx的实现。
Fx的实质是连续有序改变dom元素的属性达到视觉上的效果，动态地变化起来。这些属性主要是高度，宽度，透明度和颜色（背景色和前景色）等。连续有序是和时间相关的，也就是先在某个时间点改变一下CSS的样式属性，下一个时间点再改变一下样式属性，达到渐变的过程的效果。

Jquery为我们提供了几种常用的FX的函数。
Slide是滑出的动作，对于slide，jquery提供了slideDown、slideUp、slideToggle三种方法。slideDown是元素向下面渐渐地滑出，最后全部可见。slideUp是元素向上面渐渐地钻进去，最后不见。slideToggle则是这两者之间的转换了。
Fade是淡变的动作。对于Fade，jquery提供了fadeIn、fadeOut两个方法。fadeIn是从无到有渐渐地显示出整个元素。fadeOut相反，它从有到无渐渐地消失这个元素，fade还提供了一个fadeTo用来改变透明性渐变到一个指定的值，而不是消失。
Jquery还提供一组更强大的方法。Show、hide、toggle采用一种更为优美的方式显示元素。Show是元素的宽度渐渐变成，同时高度也渐渐变大，同时透明度也渐渐从无到不透明。这种的效果是元素从一个点渐渐变大，最终完全地显示出来。Hide刚是相反，它是渐渐透明同时宽高逐渐变小，最后消失。Toggle是两者之间的转换。

jQuery.each({
	slideDown: { height:"show" },
	slideUp: { height: "hide" },
	slideToggle: { height: "toggle" },
	fadeIn: { opacity: "show" },
	fadeOut: { opacity: "hide" }
}, function( name, props ){
	jQuery.fn[ name ] = function( speed, callback ){
		return this.animate( props, speed, callback );
	};
});
	// 把所有匹配元素的不透明度以渐进方式调整到指定的不透明度，
//并在动画完成后可选地触发一个回调函数。这个动画只调整元素的不透明度。
	fadeTo: function(speed,to,callback){
		return this.animate({opacity: to}, speed, callback);
	},
Slide和fade是通过分别改变height或opacity来完成效果的。其完成的工作任务在this.animate( props, speed, callback )上。
show
对于show和hide的，它们的效果更好一点，其代码也复杂一点。
// show(speed,[callback])
	// 以优雅的动画隐藏所有匹配的元素，并在显示完成后可选地触发一个回调函数。
    // 可以根据指定的速度动态地改变每个匹配元素的高度、宽度和不透明度。
	// 显示隐藏的匹配元素 show()
show: function(speed,callback){
return speed ?
this.animate({height: "show", width: "show", opacity: "show"
			          }, speed, callback)
 : this.filter(":hidden").each(function(){
	  this.style.display = this.oldblock || "";
		if ( jQuery.css(this,"display") == "none" ) {
		   var elem = jQuery("&lt;" + this.tagName + " /&gt;").appendTo("body");
		   this.style.display = elem.css("display");// 默认的显示的display
	     	if (this.style.display == "none")// 显式地设定该tag不显示						this.style.display = "block";
			   	elem.remove();// 上面这些的处理有没有必要呢？
				}
			}).end();// 回到前一个jQuery对象
	},
hide: function(speed,callback){
	 return speed ?
		this.animate({height: "hide", width: "hide", opacity: "hide"
			    }, speed, callback)
 :	this.filter(":visible").each(function(){
			this.oldblock = this.oldblock || jQuery.css(this,"display");
				this.style.display = "none";
			}).end();
	},
toggle: function( fn, fn2 ){
return jQuery.isFunction(fn) &amp;&amp; jQuery.isFunction(fn2) ?
	this._toggle.apply( this, arguments ) :// 原来的toggle
		(fn ?   this.animate({height: "toggle", width: "toggle",
 opacity: "toggle"}, fn, fn2)
	 :  this.each(function(){jQuery(this)[ jQuery(this).is(":hidden") ?
 "show" : "hide" ]();}
			// 对每个元素都调用show,或hide函数。
			)
		);
	},
show和hide的函数如果没有指定speed的参数，它们就直接地show或hide元素。没有动画的效果。如果给定的speed的参数。它能根据这个speed的值动态去改变高度宽度透明度来达到动画的show或hide的效果。Toggle则是这两样的变换。
  prk/彭仁夔            转载请注明出处  <a href="http://jljlpch.javaeye.com/">http://jljlpch.javaeye.com/</a>
</pre>
<pre name="code" class="java">8.2 Fx的核心源码分析
上面的几个常用方式都是调用了this.animate。jquery对象的animate是大包大揽的函数。所有的FX的效果都可以从这里得到。因为FX特效就是通过连续（间隔很小的时间点）去改变元素的CSS的样式。达到视觉上的效果。Animate就是根据指定的参数（如speed,元素的属性的变化范围）来完成这样的功能。
Animate
/**
	 * 用于创建自定义动画的函数。
	 * 这个函数的关键在于指定动画形式及结果样式属性对象。这个对象中每个属性都表示一个可以变化的样式属性（如“height”、“top”或“opacity”）。
	 * 注意：所有指定的属性必须用骆驼形式，比如用marginLeft代替margin-left.
	 * 而每个属性的值表示这个样式属性到多少时动画结束。如果是一个数值，样式属性就会从当前的值渐变到指定的值。如果使用的是“hide”、“show”或“toggle”这样的字符串值，则会为该属性调用默认的动画形式。
	 * 在 jQuery 1.2 中，你可以使用 em 和 % 单位。另外，在 jQuery 1.2 中，你可以通过在属性值前面指定 "+=" 或
	 * "-=" 来让元素做相对运动。
	 * 
	 * params (Options) : 一组包含作为动画属性和终值的样式属性和及其值的集合 。 duration (String,Number)
	 * :(可选) 三种预定速度之一的字符串("slow", "normal", or "fast")或表示动画时长的毫秒数值(如：1000)
	 * easing (String) : (可选) 要使用的擦除效果的名称(需要插件支持).默认jQuery提供"linear" 和 "swing".
	 * callback (Function) : (可选) 在动画完成时执行的函数
	 */
animate: function( prop, speed, easing, callback ) {
	var optall = jQuery.speed(speed, easing, callback); ①
// 执行each或queue方法
return this[ optall.queue === false ? "each" : "queue" ](function(){②	var opt = jQuery.extend({}, optall), p,
	hidden=this.nodeType==1&amp;&amp;jQuery(this).is(":hidden"),//元素节点且隐藏
	self = this;// 当前的元素
	for ( p in prop ) {                                        ③
	  //如果是完成的状态，就直接调用complate函数
	  if ( prop[p] == "hide" &amp;&amp; hidden || prop[p] == "show" &amp;&amp; !hidden )		  return opt.complete.call(this);
	 if (( p == "height" || p == "width")&amp;&amp; this.style ){//style高宽度
		opt.display = jQuery.css(this, "display");// 保存当前元素的display
		opt.overflow = this.style.overflow;// 保证没有暗中进行的
		}
	 }
	if ( opt.overflow != null )// 超出部分不见
		this.style.overflow = "hidden";
opt.curAnim = jQuery.extend({}, prop);//clone传入的参数prop
   	jQuery.each( prop, function(name, val){              ④
// 对当前元素的给定的属性进行变化的操作
		var e = new jQuery.fx( self, opt, name );       ⑤
// 传参的属性可以用toggle，show，hide，其它
	  // 调用当前e.show,e.hide,e.val的方法，jQuery.fx.prototype
         if ( /toggle|show|hide/.test(val) )          ⑥
			e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop );		else {                                             ⑦
			var parts = al.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),
			start = e.cur(true) || 0;// 当前元素当前属性的值
            // +=" 或 "-=" 来让元素做相对运动。
			if ( parts ) {                                       ⑧
				var end = parseFloat(parts[2]),	unit = parts[3] || "px";				if ( unit != "px" ) {// 计算开始的值=(end/cur)*start
					self.style[ name ] = (end || 1) + unit;
					start = ((end || 1) / e.cur(true)) * start;
					self.style[ name ] = start + unit;
					}
		    if( parts[1]) end = ((parts[1] == "-="? -1 : 1)* end)+ start;
			e.custom( start, end, unit );// 动画
		 } 
		//直接计算start和end的位置来动画。val是数值的end,start当前的属性值。
		else	e.custom( start, val, "" );// 动画    ⑨
		}
	});
	/ For JS strict compliance
return true;
});	},

Animate通过传入的参数对于jquery对象中的每个元素的每个指示的属性都进行时间上渐变的改变。下面就分析其中的代码。
jQuery.speed
在①是就通过jquery.speed来进行参数的统一整理。
// 主要用于辅助性的工作
speed: function(speed, easing, fn) {
	var opt = speed &amp;&amp; speed.constructor == Object ? speed : {	
// coplete是至多三个参数的最后一个。看看是否传入动画完成回调的函数
    complete: fn ||!fn &amp;&amp; easing ||jQuery.isFunction( speed ) &amp;&amp; speed,
duration: speed,// 持继的时间，动画运行的时间。
//找到动画中属性随时间渐变的的算法。
easing:fn&amp;&amp;easing || easing &amp;&amp; easing.constructor != Function &amp;&amp; easing
	};
//计算出正确的duration，它支持fast,slow这样已经定义的常量
opt.duration = (opt.duration &amp;&amp;
 (opt.duration.constructor == Number?
opt.duration :
jQuery.fx.speeds[opt.duration]))||jQuery.fx.speeds._default; 
		// Queueing
		opt.old = opt.complete;
//这里是把complete形成了包裹，看看参数中是否指定队列操作，
//如果先出列，再执行complete
opt.complete = function(){
//可能通过参数指定queue，this指向是当前的dom元素。
	if ( opt.queue !== false )	jQuery(this).dequeue();//出queue
	if (jQuery.isFunction( opt.old ))	opt.old.call( this );
	};

return opt;
},
jquery.speed是对参数进行管理的操作函数。它首先看看speed是不是紧缩型的参数如{ complete:xx, easing:xx, duration:xx}。如果不是，就根据传入的参数进行判断，组成紧缩型的对象参数。
   由于jquery对象支持fast,slow这样的常量来代替具体的speed的数值，第二步就是进行speed的处理。如果没有提供就提供默认的speed。其代码在jQuery.fx.speeds中speeds:{	slow: 600,	fast: 200,	_default: 400},定义了三种形式的速度。
接下来是对在完成的时间执行的complete的回调函数进行包裹。包裹就是看看参数中提供了队列的操作没有。提供了就进行出队列的操作。之后再执行complete的回调函数。
jQuery.fn.dequeue = function(type){
	type = type || "fx";
	return this.each(function(){
		var q = queue(this, type);// 得取type的的值
		q.shift();// 移出一个
		if ( q.length )
			q[0].call( this );
	});
};
jQuery.fn.dequeue根据type取到当前dom元素的queue。先移出一个。再运行queue中的第一个。
Queue</pre>
<pre name="code" class="java">  prk/彭仁夔            转载请注明出处  <a href="http://jljlpch.javaeye.com/">http://jljlpch.javaeye.com/</a>

在②处和上一部分都看看参数中提供了队列的操作没有，有就是进行queue的操作。Queue的操作和each的操作是不一样的。
// 实现队列操作，为jQuery对象中的每个元素都加type的属性，值为fn.
queue: function(type, fn){
	// 可能看出支持一个参数的fn或array形式的集合其type为默认的fx的形式。
	if(jQuery.isFunction(type)||( type &amp;&amp; type.constructor == Array)) {
		    	fn = type;	type = "fx";	}
	//没有参数时或一个参数是字符的type时就从jquery对象第一个元素的data中取
    //出相对于的type(空就是所有)的队列中的元素（fn）。
	if ( !type || (typeof type == "string" &amp;&amp; !fn) )
		return queue( this[0], type );//从queue取出
//把fn保存在jquery对象中的每个元素的data中的对应的type中去。
//对于fn是fn的数组集合，就直接设定data中type为fn的数组
//如果是单个的fn,那么就采用追加的形式追加到data的type的fn数组中。
//如果追加的形式，而且之前数组中没有fn元素。那么就执行这个元素。
return this.each(function(){
	if ( fn.constructor == Array )// 数组的形式
		 queue(this, type, fn);// 存储在元素的type属性中
	else {
		  queue(this, type).push( fn );
			if ( queue(this, type).length == 1 )	fn.call(this);
			}
		});
	},
分析上面的代码可以看出Queue的操作和each的操作是不太一样的。Each是对每个元素都执行fn函数。而queue对于每个元素都把fn函数放到自已对应的cache中fx的属性中保存，是单个的fn的话，也立马运行。在②处和each的作用差不多。
在上面的代码，它还调用了queue(this, type, fn);来实现把把fn存到this元素的data中的对应的type中去。
// 为元素加上type的array的属性，或返回取到elem上type的值
var queue = function( elem, type, array ) {
	if ( elem ){
		type = type || "fx";
		var q = jQuery.data( elem, type + "queue" );
		if ( !q || array )
			q = jQuery.data( elem, type + "queue", jQuery.makeArray(array) );
	}
	return q;
};
这个全局的函数就是在jQuery.data进一步封装，使它支持默认的fx type和array的类数组的参数。
Jquery这里的Queue实质上没有起到什么作用。它本来可以支持一个元素的的连续执行几个Queue的函数达到更丰富的动画的效果。估计这里是没有完成。
①②③④⑤⑥⑦⑧⑨⑩
jQuery.fx
⑤处animate为dom元素的每个指定的属性都生成了一个fx对象。
// 根据参数构成一个对象
	fx: function( elem, options, prop ){
		this.options = options;
		this.elem = elem;
		this.prop = prop;

		if ( !options.orig )
			options.orig = {};
	}
Fx函数是一个构建函数，仅仅是把参数变成本对象的属性。以便于fx对象的其它方法来使用这些参数。在⑥处就是通过调用fx的方法show或hidden来完成一个属性的逐渐的改变。在⑨是通过custom方法来直接进行一个动画。
先看一下show或hidden：
show: function(){
// 保存当前的，以被修改之后能得到初始的值
this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);
this.options.show = true;//标明是进行show操作
this.custom(0, this.cur());
//让最开始时以1px的宽或高度来显示。防止内容flash
if ( this.prop == "width" || this.prop == "height" )
		this.elem.style[this.prop] = "1px";		
jQuery(this.elem).show();
	},
hide: function(){
// 保存当前的，以被修改之后能得到初始的值
this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);
this.options.hide = true;//标识是进行hide操作
this.custom(this.cur(), 0);	},
show和hide是在指定元素的属性为show或hide的时候调用的，如height: "show", width: "show", opacity: "show"。它们都是先保存原始的改悔。之后调用custom来完成动画。和⑨处是一样的。
也就是说完成动画的工作在custom中：
// 开动一个动画
	custom: function(from, to, unit){
		this.startTime = now();//动画开始的时候
		this.start = from;//位置开始点
		this.end = to;//位置结果点
		this.unit = unit || this.unit || "px";
		this.now = this.start;//位置当前点
		//state是时间间隔在总的duration的比率
		//pos是按一定算法把时间上的比率折算到位置上的比率
		this.pos = this.state = 0;
		//根据this.now位置当前点的值来设定元素的属性显示出来
		this.update();

		var self = this;
		function t(gotoEnd){
			return self.step(gotoEnd);// 调用step(gotoEnd)//本对象的
		}
		t.elem = this.elem;//删除的时候做判断用
		//timers栈是公共的，不同的元素的不同的属性step都是放在这里面。
		jQuery.timers.push(t);
         
		if ( jQuery.timerId == null ) {
			jQuery.timerId = setInterval(function(){
				var timers = jQuery.timers;
			//倒是觉得这里会有同步冲突的问题。Ext.observable中就有解决方法
				for ( var i = 0; i &lt; timers.length; i++ ) 
				//当一个属性的动画完成，或强迫完成的时候，把step从数组中删除.
				//同时把i的位置不改变。继续下一个。
				if ( !timers[i]() )	timers.splice(i--, 1);		               
				  //说明还有属性的动画没有完成，step还在timers中。
				  //那么就不clearInterval，13ms之后再继续。直到数组
				  //中所有的step都被删除。
				if ( !timers.length ) {
					clearInterval( jQuery.timerId );
					jQuery.timerId = null;
				}
			}, 13);
		}
	},
在custom中为fx对象动态地追加了几个属性。Start和end属性指的属性值变化的开始和结束位置。这是属性值发生变化的范围。Now是在Start和end 范围的某一个点，也就是当前要比属性设定值。这个值是根据时间的间隔比率再通过一定的算法来得出的。pos 和state一个是位置上的比率，一个是时间上比率，值在0~1之间。
Custom通过this.now = this.start;和this.update();来设起始位置的样式属性。
// 为元素设值，更新显示
	update: function(){
		//可以在显示之前进行自定义的显示操作
		//这里可以是改变this.now或元素的其它属性。
		//改变this.now是改变动画的轨迹，改变其它的属性会有更多的效果
		if ( this.options.step )
			this.options.step.call( this.elem, this.now, this );
         //根据this.now来改变/设值当前属性的值。也就改变了样式。
		(jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );

		// 对于高度和宽度，肯定是要能看出效果的，故采用display=block。
		if ( ( this.prop == "height" || this.prop == "width" ) 
&amp;&amp; this.elem.style )
			this.elem.style.display = "block";
	},</pre>
<pre name="code" class="java">  prk/彭仁夔            转载请注明出处  <a href="http://jljlpch.javaeye.com/">http://jljlpch.javaeye.com/</a>

通过udate设定起始位置的样式属性之后，custom第二步就是采用setInterval
每隔13ms就执行一次当前的fx对象的step方法。该方法实现了动画结束的扫尾工作和动画过程中按一定的算法来计算this.now的值。因为这个值的改变，之后调用update就可以改变样式的属性。
这样一来，就实现了元素的某个属性的渐变过程。
// 动画的每一个步骤
	step: function(gotoEnd){
		var t = now();//运行到当前的时间，因为是13ms才运行一次。
         // 强行指定结束或当前时间大于startTime+duration
		if ( gotoEnd || t &gt; this.options.duration + this.startTime ) {
			this.now = this.end;//当前的位置为结束位置
			this.pos = this.state = 1;//当前的state,pos的比率为1.最大。
			this.update();//显示
            //标识这个属性的动画已经完成
			this.options.curAnim[ this.prop ] = true;
            //再一次判断是否完成
			var done = true;
			for ( var i in this.options.curAnim )
				if ( this.options.curAnim[i] !== true )
					done = false;

			if ( done ) {				
				if ( this.options.display != null ) {//  恢复overflow
					this.elem.style.overflow = this.options.overflow;
					// 恢复 display
					this.elem.style.display = this.options.display;
					//判断其是否恢复成功，
					if ( jQuery.css(this.elem, "display") == "none" )
						this.elem.style.display = "block";
				}

				//如果是hide的操作
				if ( this.options.hide )
					this.elem.style.display = "none";
				
					//如果元素已经show或hide,恢复其动画改变的属性
				if ( this.options.hide || this.options.show )
					for ( var p in this.options.curAnim )
						jQuery.attr(this.elem.style, p, 
this.options.orig[p]);
			}

			if ( done )// 运行complete的回调函数
				this.options.complete.call( this.elem );

			return false;
		} else {
			var n = t - this.startTime;//时间间隔
			this.state = n / this.options.duration;//时间间隔比率

			//根据时间间隔的比率再按一定的算法比率来计算
//当前的运动的位置点的比率。默认是swing的算法
			this.pos = jQuery.easing[this.options.easing || 
			(jQuery.easing.swing ? "swing" : "linear")]
(this.state, n, 0, 1, this.options.duration);
		    //当前的位置
			this.now = this.start + ((this.end - this.start) * this.pos);

			// 显示
			this.update();
		}

		return true;
	}
Step中第一部分是完成时的扫尾工作，恢复动画时改变的属性和运行complete的回调函数。第二部分就是计算this.now的值之后显示出来。目前jquery提供了两种算法来计算从时间间隔比率转换成位置上的比率。
	easing: {
		linear: function( p, n, firstNum, diff ) {
			return firstNum + diff * p;
		},
		swing: function( p, n, firstNum, diff ) {
			return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
		}
	},
这就是它的算法。对于linear的形式，Jquery采用了1:1的关系来计算的。
Stop
  一个动画，有的时间可能会出现在没有运行完成就中断。Stop就是对这个进行操作的。
stop: function(clearQueue, gotoEnd){
	var timers = jQuery.timers;
	if (clearQueue)	this.queue([]);// 清除
		this.each(function(){
		//倒序是为了能把在loop过程加入timers的当前元素的属性的动画step也给删除。
			for ( var i = timers.length - 1; i &gt;= 0; i-- )
				if ( timers[i].elem == this ) {
					if (gotoEnd) timers[i](true); // 强迫动画结束	
					 timers.splice(i, 1);
				}
		});
		// start the next in the queue if the last step wasn't forced
		if (!gotoEnd)		this.dequeue();

		return this;
	}
在stop中，我们可以看出step（force）中的参数的作用。这个强迫动画到最后一步，即动画结束进行扫尾工作。这里的jQuery.timers是公共的集合。在custom中的setInterval就是对它进行操作的。
</pre>
<p>&nbsp;</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://jljlpch.javaeye.com/blog/234130#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 28 Aug 2008 19:37:47 +0800</pubDate>
        <link>http://jljlpch.javaeye.com/blog/234130</link>
        <guid>http://jljlpch.javaeye.com/blog/234130</guid>
      </item>
      <item>
        <title>jqueyr fx源码（修改）</title>
        <author>jljlpch</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jljlpch.javaeye.com">jljlpch</a>&nbsp;
          链接：<a href="http://jljlpch.javaeye.com/blog/234128" style="color:red;">http://jljlpch.javaeye.com/blog/234128</a>&nbsp;
          发表时间: 2008年08月28日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">/*
 * author：prk date:2008-08-07 comment:analyse the fx of jQuery.
 * 
 */
jQuery.fn.extend({
	
	// show(speed,[callback])
	// 以优雅的动画隐藏所有匹配的元素，并在显示完成后可选地触发一个回调函数。
    // 可以根据指定的速度动态地改变每个匹配元素的高度、宽度和不透明度。
	// 显示隐藏的匹配元素 show()
	show: function(speed,callback){
		return speed ?
			this.animate({
				height: "show", width: "show", opacity: "show"
			}, speed, callback) :

			this.filter(":hidden").each(function(){
				this.style.display = this.oldblock || "";
				if ( jQuery.css(this,"display") == "none" ) {
					var elem = jQuery("&lt;" + this.tagName + " /&gt;").appendTo("body");
					this.style.display = elem.css("display");// 默认的显示的display
					// handle an edge condition where css is - div {
					// display:none; } or similar
					if (this.style.display == "none")// 处理显式地设定了该tag不显示，只好采用b
						this.style.display = "block";
					elem.remove();// 上面这些的处理有没有必要呢？
				}
			}).end();// 回到前一个jQuery对象
	},
	
    // 与show相反
	hide: function(speed,callback){
		return speed ?
			this.animate({
				height: "hide", width: "hide", opacity: "hide"
			}, speed, callback) :

			this.filter(":visible").each(function(){
				this.oldblock = this.oldblock || jQuery.css(this,"display");
				this.style.display = "none";
			}).end();
	},

	// Save the old toggle function
	_toggle: jQuery.fn.toggle,
      /*  prk/彭仁夔            转载请注明出处 <span><a href="http://jljlpch.javaeye.com/*/">http://jljlpch.javaeye.com/*/</a></span></pre>
<pre name="code" class="java">	// 切换元素的可见状态。
    // 如果元素是可见的，切换为隐藏的；如果元素是隐藏的，切换为可见的。
	
	// 每次点击后依次调用函数。
    // 如果点击了一个匹配的元素，则触发指定的第一个函数，当再次点击同一元素时，则触发指定的第二个函数，
    // 如果有更多函数，则再次触发，直到最后一个。随后的每次点击都重复对这几个函数的轮番调用。
    // 可以使用unbind("click")来删除。
	toggle: function( fn, fn2 ){
		return jQuery.isFunction(fn) &amp;&amp; jQuery.isFunction(fn2) ?
			this._toggle.apply( this, arguments ) :// 原来的toggle
			(fn ?
			   this.animate({height: "toggle", width: "toggle", opacity: "toggle"}, fn, fn2)
			:  this.each(function(){jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();}
			// 对每个元素都调用show,或hide函数。
			)
		);
	},

	// 把所有匹配元素的不透明度以渐进方式调整到指定的不透明度，并在动画完成后可选地触发一个回调函数。
     // 这个动画只调整元素的不透明度，也就是说所有匹配的元素的高度和宽度不会发生变化。
	fadeTo: function(speed,to,callback){
		return this.animate({opacity: to}, speed, callback);
	},
	
	/**
	 * 用于创建自定义动画的函数。
	 * 这个函数的关键在于指定动画形式及结果样式属性对象。这个对象中每个属性都表示一个可以变化的样式属性（如“height”、“top”或“opacity”）。
	 * 注意：所有指定的属性必须用骆驼形式，比如用marginLeft代替margin-left.
	 * 而每个属性的值表示这个样式属性到多少时动画结束。如果是一个数值，样式属性就会从当前的值渐变到指定的值。如果使用的是“hide”、“show”或“toggle”这样的字符串值，则会为该属性调用默认的动画形式。
	 * 在 jQuery 1.2 中，你可以使用 em 和 % 单位。另外，在 jQuery 1.2 中，你可以通过在属性值前面指定 "+=" 或
	 * "-=" 来让元素做相对运动。
	 * 
	 * params (Options) : 一组包含作为动画属性和终值的样式属性和及其值的集合 。 duration (String,Number)
	 * :(可选) 三种预定速度之一的字符串("slow", "normal", or "fast")或表示动画时长的毫秒数值(如：1000)
	 * easing (String) : (可选) 要使用的擦除效果的名称(需要插件支持).默认jQuery提供"linear" 和 "swing".
	 * callback (Function) : (可选) 在动画完成时执行的函数
	 */
	animate: function( prop, speed, easing, callback ) {
		var optall = jQuery.speed(speed, easing, callback);

		return this[ optall.queue === false ? "each" : "queue" ](function(){// 执行each或queue方法
			var opt = jQuery.extend({}, optall), p,
				hidden = this.nodeType == 1 &amp;&amp; jQuery(this).is(":hidden"),// 是元素节点且是隐藏的
				self = this;// 当前的元素
	
			for ( p in prop ) {
				//如果是完成的状态，就直接调用complate函数
				if ( prop[p] == "hide" &amp;&amp; hidden || prop[p] == "show" &amp;&amp; !hidden )// 已经是
					return opt.complete.call(this);//，在用户的callback加上队列的处理

				if ( ( p == "height" || p == "width" ) &amp;&amp; this.style ) {// style中高度，宽度
					opt.display = jQuery.css(this, "display");// 保存当前元素的display
					opt.overflow = this.style.overflow;// 保证没有暗中进行的
				}
			}
			if ( opt.overflow != null )// 超出部分不见
				this.style.overflow = "hidden";

			opt.curAnim = jQuery.extend({}, prop);//clone传入的参数prop
   
			jQuery.each( prop, function(name, val){// 对当前元素的给定的属性进行变化的操作
				var e = new jQuery.fx( self, opt, name );
                
				if ( /toggle|show|hide/.test(val) )// 传参的属性可以用toggle，show，hide，其它
				// 调用当前e.show,e.hide,e.val的方法，jQuery.fx.prototype
					e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop );					
				else {// 支持"+=" 或 "-=" 来让元素做相对运动。
					var parts = val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),
						start = e.cur(true) || 0;// 当前元素当前属性的值
                      // +=" 或 "-=" 来让元素做相对运动。
					if ( parts ) {
						var end = parseFloat(parts[2]),// 值
							unit = parts[3] || "px";// 单位
						
						if ( unit != "px" ) {// 计算开始的值=(end/cur)*start
							self.style[ name ] = (end || 1) + unit;
							start = ((end || 1) / e.cur(true)) * start;
							self.style[ name ] = start + unit;
						}

						if ( parts[1] )// +=/-=,做相对运行
							end = ((parts[1] == "-=" ? -1 : 1) * end) + start;

						e.custom( start, end, unit );// 动画
					} 
					//直接计算start和end的位置来动画。val是数值的end,start当前的属性值。
					else
						e.custom( start, val, "" );// 动画
				}
			});
			// For JS strict compliance
			return true;
		});
	},

	// 实现队列操作，为jQuery对象中的每个元素都加type的属性，值为fn.
	queue: function(type, fn){
		// 可能看出支持一个参数的fn或array形式的集合其type为默认的fx的形式。
		if ( jQuery.isFunction(type) || ( type &amp;&amp; type.constructor == Array )) {
			fn = type;
			type = "fx";
		}
		// type不存在,空字符等，无参数，type:string,fn不存在。肯定不是函数，也不是数组
		if ( !type || (typeof type == "string" &amp;&amp; !fn) )
			return queue( this[0], type );//从queue取出

		return this.each(function(){
			//fn是数组的形式fn集合，直接构建queue
			if ( fn.constructor == Array )// 数组的形式
				queue(this, type, fn);// 存储在元素的type属性中
			  //取得queue,后push，只有一个立即运行。
			else {
				queue(this, type).push( fn );
				if ( queue(this, type).length == 1 )
					fn.call(this);
			}
		});
	},

	stop: function(clearQueue, gotoEnd){
		var timers = jQuery.timers;

		if (clearQueue)
			this.queue([]);// 清除

		this.each(function(){
			//倒序是为了能把在loop过程加入timers的当前元素的属性的动画step也给删除。
			for ( var i = timers.length - 1; i &gt;= 0; i-- )
				if ( timers[i].elem == this ) {
					if (gotoEnd) timers[i](true);
						// 强迫动画结束						
					timers.splice(i, 1);
				}
		});
		// start the next in the queue if the last step wasn't forced
		if (!gotoEnd)
			this.dequeue();

		return this;
	}

});

// Generate shortcuts for custom animations
jQuery.each({
	slideDown: { height:"show" },
	slideUp: { height: "hide" },
	slideToggle: { height: "toggle" },
	fadeIn: { opacity: "show" },
	fadeOut: { opacity: "hide" }
}, function( name, props ){
	jQuery.fn[ name ] = function( speed, callback ){
		return this.animate( props, speed, callback );
	};
});

// 为元素加上type的array的属性，或返回取到elem上type的值
var queue = function( elem, type, array ) {
	if ( elem ){
		type = type || "fx";
		var q = jQuery.data( elem, type + "queue" );
		if ( !q || array )
			q = jQuery.data( elem, type + "queue", jQuery.makeArray(array) );
	}
	return q;
};
// 出列，根据type
jQuery.fn.dequeue = function(type){
	type = type || "fx";
	return this.each(function(){
		var q = queue(this, type);// 得取type的的值
		q.shift();// 移出一个
		if ( q.length )
			q[0].call( this );
	});
};


jQuery.extend({
     // 主要用于辅助性的工作
	speed: function(speed, easing, fn) {
		var opt = speed &amp;&amp; speed.constructor == Object ? speed : {// 采用紧凑型方式
			complete: fn || !fn &amp;&amp; easing ||
				jQuery.isFunction( speed ) &amp;&amp; speed,// coplete是至多三个参数的最后一个，当然是Fn.
			duration: speed,// 持继的时间
			easing: fn &amp;&amp; easing || easing &amp;&amp; easing.constructor != Function &amp;&amp; easing// 不是Fn
		};

		opt.duration = (opt.duration &amp;&amp; (opt.duration.constructor == Number ?
			opt.duration :	jQuery.fx.speeds[opt.duration])) // 存在，不是数值，转找
			|| jQuery.fx.speeds._default;// 默认的

		// Queueing
		opt.old = opt.complete;
		opt.complete = function(){// 排队的处理
			if ( opt.queue !== false )//可能通过参数指定queue
				jQuery(this).dequeue();//出queue
			if ( jQuery.isFunction( opt.old ) )
				opt.old.call( this );//执行完成之后的回调
		};

		return opt;
	},

	// 擦除效果
	easing: {
		linear: function( p, n, firstNum, diff ) {
			return firstNum + diff * p;
		},
		swing: function( p, n, firstNum, diff ) {
			return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
		}
	},

	timers: [],// jQuery.timers
	timerId: null,
    
	// 根据参数构成一个对象
	fx: function( elem, options, prop ){
		this.options = options;
		this.elem = elem;
		this.prop = prop;

		if ( !options.orig )
			options.orig = {};
	}

});

jQuery.fx.prototype = {

	// 为元素设值，更新显示
	update: function(){
		//可以在显示之前进行自定义的显示操作
		//这里可以是改变this.now或元素的其它属性。
		//改变this.now是改变动画的轨迹，改变其它的属性会有更多的效果
		if ( this.options.step )
			this.options.step.call( this.elem, this.now, this );
         //根据this.now来改变/设值当前属性的值。也就改变了样式。
		(jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );

		// 对于高度和宽度，肯定是要能看出效果的，故采用display=block。
		if ( ( this.prop == "height" || this.prop == "width" ) &amp;&amp; this.elem.style )
			this.elem.style.display = "block";
	},

	// 当前元素当前属性的值
	cur: function(force){
		if ( this.elem[this.prop] != null &amp;&amp; (!this.elem.style || this.elem.style[this.prop] == null) )
			return this.elem[ this.prop ];

		var r = parseFloat(jQuery.css(this.elem, this.prop, force));
		return r &amp;&amp; r &gt; -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;
	},

	// 开动一个动画
	custom: function(from, to, unit){
		this.startTime = now();//动画开始的时候
		this.start = from;//位置开始点
		this.end = to;//位置结果点
		this.unit = unit || this.unit || "px";
		this.now = this.start;//位置当前点
		//state是时间间隔在总的duration的比率
		//pos是按一定算法把时间上的比率折算到位置上的比率
		this.pos = this.state = 0;
		//根据this.now位置当前点的值来设定元素的属性显示出来
		this.update();

		var self = this;
		function t(gotoEnd){
			return self.step(gotoEnd);// 调用step(gotoEnd)//本对象的
		}
		t.elem = this.elem;//删除的时候做判断用
		//timers栈是公共的，不同的元素的不同的属性step都是放在这里面。
		jQuery.timers.push(t);
         
		if ( jQuery.timerId == null ) {
			jQuery.timerId = setInterval(function(){
				var timers = jQuery.timers;
				//倒是觉得这里会有同步冲突的问题。Ext.observable中就有解决方法
				for ( var i = 0; i &lt; timers.length; i++ )// 执行timers中所有
				  
				//当一个属性的动画完成，或强迫完成的时候，把step从数组中删除.
				//同时把i的位置不改变。继续下一个。
				if ( !timers[i]() )					
						timers.splice(i--, 1);						
                  
				  //说明还有属性的动画没有完成，step还在timers中。
				  //那么就不clearInterval，13ms之后再继续。直到数组
				  //中所有的step都被删除。
				if ( !timers.length ) {
					clearInterval( jQuery.timerId );
					jQuery.timerId = null;
				}
			}, 13);
		}
	},

	// Simple 'show' function
	show: function(){
		// 保存当前的，以被修改之后能得到初始的值
		this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
		this.options.show = true;//标明是进行show操作
		
		this.custom(0, this.cur());
		
		//让最开始时以1px的宽或高度来显示。防止内容flash
		if ( this.prop == "width" || this.prop == "height" )
			this.elem.style[this.prop] = "1px";		
		jQuery(this.elem).show();
	},

	// 隐藏
	hide: function(){
		// 保存当前的，以被修改之后能得到初始的值
		this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
		this.options.hide = true;//标识是进行hide操作
		
		this.custom(this.cur(), 0);
	},

	// 动画的每一个步骤
	step: function(gotoEnd){
		var t = now();//运行到当前的时间，因为是13ms才运行一次。
         // 强行指定结束或当前时间大于startTime+duration
		if ( gotoEnd || t &gt; this.options.duration + this.startTime ) {
			this.now = this.end;//当前的位置为结束位置
			this.pos = this.state = 1;//当前的state,pos的比率为1.最大。
			this.update();//显示
            //标识这个属性的动画已经完成
			this.options.curAnim[ this.prop ] = true;
            //再一次判断是否完成
			var done = true;
			for ( var i in this.options.curAnim )
				if ( this.options.curAnim[i] !== true )
					done = false;

			if ( done ) {				
				if ( this.options.display != null ) {//  恢复overflow
					this.elem.style.overflow = this.options.overflow;
					// 恢复 display
					this.elem.style.display = this.options.display;
					//判断其是否恢复成功，
					if ( jQuery.css(this.elem, "display") == "none" )
						this.elem.style.display = "block";
				}

				//如果是hide的操作
				if ( this.options.hide )
					this.elem.style.display = "none";
				
					//如果元素已经show或hide,恢复其动画改变的属性
				if ( this.options.hide || this.options.show )
					for ( var p in this.options.curAnim )
						jQuery.attr(this.elem.style, p, this.options.orig[p]);
			}

			if ( done )// 运行complete的回调函数
				this.options.complete.call( this.elem );

			return false;
		} else {
			var n = t - this.startTime;//时间间隔
			this.state = n / this.options.duration;//时间间隔比率

			//根据时间间隔的比率再按一定的算法比率来计算当前的运动的位置点的比率。默认是swing的算法
			this.pos = jQuery.easing[this.options.easing || 
			(jQuery.easing.swing ? "swing" : "linear")](this.state, n, 0, 1, this.options.duration);
		    //当前的位置
			this.now = this.start + ((this.end - this.start) * this.pos);

			// 显示
			this.update();
		}

		return true;
	}

};

jQuery.extend( jQuery.fx, {
	// 动画的速度
	speeds:{
		slow: 600,
 		fast: 200,
 		// Default speed
 		_default: 400
	},
	
	// 为元素设值
	step: {
		opacity: function(fx){// 为元素CSS设opacity为fx
			jQuery.attr(fx.elem.style, "opacity", fx.now);
		},

		_default: function(fx){
			if( fx.prop in fx.elem ) // 对于元素
				fx.elem[ fx.prop ] = fx.now;
			else if( fx.elem.style )// 对于style
				fx.elem.style[ fx.prop ] = fx.now + fx.unit;
		}
	}
});
</pre>
<p>&nbsp;</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://jljlpch.javaeye.com/blog/234128#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 28 Aug 2008 19:33:47 +0800</pubDate>
        <link>http://jljlpch.javaeye.com/blog/234128</link>
        <guid>http://jljlpch.javaeye.com/blog/234128</guid>
      </item>
      <item>
        <title>jquery.ajax</title>
        <author>jljlpch</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jljlpch.javaeye.com">jljlpch</a>&nbsp;
          链接：<a href="http://jljlpch.javaeye.com/blog/233252" style="color:red;">http://jljlpch.javaeye.com/blog/233252</a>&nbsp;
          发表时间: 2008年08月27日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">7.2 jquery.ajax</pre>
<pre name="code" class="java">                prk/彭仁夔  08-08-27
这所有的最终都是通过jQuery.ajax()来完成的。
ajax : function(s) {
	//两次继承s,以便在测试中能检测
	s = jQuery.extend(true, s, jQuery.extend(true, {}, 
jQuery.ajaxSettings,	s));         ①
	var jsonp, jsre = /=\?(&amp;|$)/g, status, data,
 type = s.type	.toUpperCase();
// 如果不是字符集串就转换在查询字符集串
if (s.data &amp;&amp; s.processData &amp;&amp; typeof s.data != "string")
		s.data = jQuery.param(s.data);

// 构建jsonp请求字符集串。jsonp是跨域请求，要加上callback=？后面将会加函数名
if (s.dataType == "jsonp") {                               ②
if (type == "GET") {//使get的url包含 callback=？后面将会进行加函数名
		if (!s.url.match(jsre))
			s.url += (s.url.match(/\?/) ? "&amp;" : "?")
							+ (s.jsonp || "callback") + "=?";
			} // 构建新的s.data，使其包含callback=function name
else if (!s.data || !s.data.match(jsre))
		s.data = (s.data ? s.data + "&amp;" : "") + (s.jsonp||"callback")+ "=?";
s.dataType = "json";
}		
//判断是否为jsonp,如果是，进行处理。
if (s.dataType == "json"  
			&amp;&amp; (s.data &amp;&amp; s.data.match(jsre) || s.url.match(jsre))) {③
	 jsonp = "jsonp" + jsc++;
/ /为请求字符集串的callback=加上生成回调函数名
	if (s.data)s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
	s.url = s.url.replace(jsre, "=" + jsonp + "$1");

			// 我们需要保证jsonp 类型响应能正确地执行
	//jsonp的类型必须为script。这样才能执行服务器返回的
	//代码。这里就是调用这个回调函数。
	s.dataType = "script";
//window下注册一个jsonp回调函数有，让ajax请求返回的代码调用执行它，
	//在服务器端我们生成的代码 如callbackname(data);形式传入data.
	window[jsonp] = function(tmp) {
		data = tmp;success();complete();
	// 垃圾回收,释放联变量，删除jsonp的对象，除去head中加的script元素
	   window[jsonp] = undefined;
		try {	delete window[jsonp];
			} catch (e) {	}
		if (head)	head.removeChild(script);
		};
	}

if (s.dataType == "script" &amp;&amp; s.cache == null)	s.cache = false;
// 加上时间戳，可见加cache:false就会加上时间戳
if (s.cache === false &amp;&amp; type == "GET") {
	var ts = now();
	var ret = s.url.replace(/(\?|&amp;)_=.*?(&amp;|$)/, "$1_=" + ts + "$2");
	// 没有代替，就追加在url的尾部
	s.url = ret+ ((ret == s.url) ? (s.url.match(/\?/) ? "&amp;" : "?") + "_="
						+ ts : "");
	}
// data有效，追加到get类型的url上去
if (s.data &amp;&amp; type == "GET") {
		s.url += (s.url.match(/\?/) ? "&amp;" : "?") + s.data;
		// 防止IE会重复发送get和post data
		s.data = null;
		}
// 监听一个新的请求
if (s.global &amp;&amp; !jQuery.active++) jQuery.event.trigger("ajaxStart");④
// 监听一个绝对的url,和保存domain
var parts = /^(\w+:)?\/\/([^\/?#]+)/.exec(s.url);
// 如果我们正在请求一个远程文档和正在load json或script通过get类型
//location是window的属性，通过和地址栏中的地址比较判断是不是跨域。
if (s.dataType == "script"	&amp;&amp; type == "GET"&amp;&amp; parts	&amp;&amp; (parts[1] &amp;&amp; 
parts[1] != location.protocol || parts[2] != location.host)) {⑤
		// 在head中加上&lt;script src=""&gt;&lt;/script&gt;
		var head = document.getElementsByTagName("head")[0];
		var script = document.createElement("script");
		script.src = s.url;
		if (s.scriptCharset)	script.charset = s.scriptCharset;
		//如果datatype不是jsonp，但是url却是跨域的。采用scriptr的
		//onload或onreadystatechange事件来触发回调函数。
	   if (!jsonp) {
			var done = false;
			// 对所有浏览器都加上处理器
			script.onload = script.onreadystatechange = function() {
			if (!done&amp;&amp; (!this.readyState || this.readyState == "loaded" 
|| this.readyState == "complete")) {
					done = true;	success();
					complete();head.removeChild(script);
				}
		};
	}
	head.appendChild(script);
// 已经使用了script 元素注射来处理所有的事情
	return undefined;
}
var requestDone = false;
// 创建request,IE7不能通过XMLHttpRequest来完成，只能通过ActiveXObject
var xhr = window.ActiveXObject                               ⑥
		? new ActiveXObject("Microsoft.XMLHTTP"): new XMLHttpRequest();
// 创建一个请求的连接，在opera中如果用户名为null会弹出login窗口中。
if (s.username)xhr.open(type, s.url, s.async, s.username, s.password);
else	xhr.open(type, s.url, s.async);
// try/catch是为防止FF3在跨域请求时报错
try {// 设定Content-Type                                              ⑦
	if (s.data)
		xhr.setRequestHeader("Content-Type", s.contentType);
		// 设定If-Modified-Since
	if (s.ifModified)
		xhr.setRequestHeader("If-Modified-Since",
			jQuery.lastModified[s.url]|| "Thu, 01 Jan 1970 00:00:00 GMT");
// 这里是为了让服务器能判断这个请求是XMLHttpRequest
	xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
// 设定 Accepts header 。指能接收的content-type，在服务器端设定
	xhr.setRequestHeader("Accept", s.dataType &amp;&amp; s.accepts[s.dataType]
			? s.accepts[s.dataType] + ", */*": s.accepts._default);
} catch (e) {}
//拦截方法，我们可以在send之前进行拦截。返回false就不send
if (s.beforeSend &amp;&amp; s.beforeSend(xhr, s) === false) {         ⑧
	// 清除active 请求计数
	s.global &amp;&amp; jQuery.active--;
	xhr.abort();
	return false;
}

// 触发全局的ajaxSend事件
if (s.global)	jQuery.event.trigger("ajaxSend", [xhr, s]);
// 等待response返回，主要是为后面setInterval用。
var onreadystatechange = function(isTimeout) {           ⑨
// 接收成功或请求超时
if (!requestDone &amp;&amp; xhr&amp;&amp; (xhr.readyState == 4 ||isTimeout == "timeout")) {	requestDone = true;
		 //清除定时器
		if (ival) {clearInterval(ival);		ival = null;	}
	// 分析status:tiemout--&gt;error--&gt;notmodified--&gt;success
	status = isTimeout == "timeout" ? "timeout" : !jQuery
		ttpSuccess(xhr) ? "error" : s.ifModified&amp;&amp; jQuery.
httpNotModified(xhr, s.url)	? "notmodified": "success";
    	//如果success且返回了数据，那么分析这些数据
	if (status == "success") {					
		try {	data = jQuery.httpData(xhr, s.dataType, s);
			 } catch (e) {	status = "parsererror";	}
	}
// 分析数据成功之后,进行last-modified和success的处理。				
	if (status == "success") {
		var modRes;
		  try {modRes = xhr.getResponseHeader("Last-Modified");
			} catch (e) {	//FF中如果head取不到，会抛出异常} 
		 //保存last-mordified的标识。
		if (s.ifModified &amp;&amp; modRes)jQuery.lastModified[s.url] = modRes;
	   // JSONP 有自己的callback
	    if (!jsonp) success();
	} else	// 失败时的处理
	jQuery.handleError(s, xhr, status);
// 无论如何都进行cpmplate.timeout和接收成功
	complete();
if (s.async)	xhr = null; // 防内存泄漏
}
};
if (s.async) {
// 这里是采用poll的方式，不是push的方式
//这里为什么不采用onreadystatechange？
var ival = setInterval(onreadystatechange, 13);
//如果过了timeout还没有请求到，会中断请求的。
	if (s.timeout &gt; 0)
		setTimeout(function() {					
			if (xhr) {	xhr.abort();
				if (!requestDone)	onreadystatechange("timeout");	}
		}, s.timeout);
	}
// 发送
try {xhr.send(s.data); catch(e){jQuery.handleError(s,xhr,null,e);} ⑩
// firefox 1.5 doesn't fire statechange for sync requests
if (!s.async)	onreadystatechange();
function success() {
	// 调用构建请求对象时指定的success回调。
	if (s.success)	s.success(data, status);
	// 执行全局的回调
	if (s.global)	jQuery.event.trigger("ajaxSuccess", [xhr, s]);
	}
function complete() {
	// 本地的回调
	if (s.complete)	s.complete(xhr, status);
	// 执行全局的回调
	if (s.global)	jQuery.event.trigger("ajaxComplete", [xhr, s]);
	// 全局的ajax计数器
	if (s.global &amp;&amp; !--jQuery.active)jQuery.event.trigger("ajaxStop");
	}
// return XMLHttpRequest便进行about()或其它操作.
return xhr;
},
Jquery.ajax是大包大揽的非常复杂的一个方法。它并没有像其它的lib一样，把每个小部分都分开来。它是整个都整在一个函数中。看起来很多，实际上上也没有脱离前面所说的ajax的请求的五步。它的很大一部分代码在处理跨域请求的处理上。下面就分别就ajax的代码进行分析。
ajaxSettings
在①处通过继承的方式把传入参数s和默认的jQuery.ajaxSettings都clone到s变量中。S的同名属性会覆盖jQuery.ajaxSettings的同名属性。这里两次继承s,以便在测试中能检测。
//默认的ajax的请求参数
	ajaxSettings : {
		url : location.href,//默认是地址栏中url
		global : true,//默认支持全局的ajax事件
		type : "GET",
		timeout : 0,
		contentType : "application/x-www-form-urlencoded",	
	 processData : true,
		async : true,
		data : null,
		username : null,
		password : null,
		accepts : {
			xml : "application/xml, text/xml",
			html : "text/html",
			script : "text/javascript, application/javascript",
			json : "application/json, text/javascript",
			text : "text/plain",
			_default : "*/*"
		}
这是默认的ajax的设定，我们要在参数s设定同名的属性来覆盖这些属性。但是我们不能覆盖accepts。这个会在后面的代码用到。我们可以通过设定s.dataType等于accepts中的某一个属性key指定请求的data类型，如xml,html,script,json,text。dataType还支持默认的_default和跨域的jsonp。不过其最终会解析成script。
scriptTag
②~⑥是处理跨域请求的部分。对于dataType为jsonp的类型，给其请求的字符串（可能是s.data）加上callback=callbackfn的key/value串，然后在window下注册一个callbackfn的函数。这个函数的形式如callbackfn(data){ data = tmp;success();complete();}。它代理了通过ajax(s)的传入s参数中success();complete()的功能。它就是调用这个函数，实际上是调用success();complete()的函数。
那么怎么调用呢？ajax不支持跨域。在⑤处，我们可以看到这里是采用scriptTag的方式来完成。先在页面的&lt;head&gt;中添加一个&lt;script src=url /&gt;的标签。因为在&lt;head&gt;中。浏览器会自动载入并运行请求返回的script。如果是jsonp的形式，服务器端还要动态生成的content-type为script的代码：callbackfn(data);只有这样才会调用在window中注册的函数callbackfn。同时传入所需要的参数。
如dataType == "script"形式的跨域，那只能是通过script.onload 或 script.onreadystatechange事件来触发回调。这里我们可以通过服务器返回的script代码：var data=xxx。来传递参数给s.success();s.complete()。Jquery这里采用是全局变量data来进行操作的。
Ajax Event
④是采用了jQuery.event.trigger("ajaxStart");来触发全局的ajaxStart事件。这也是说只要注册了这个事件的元素，在任何的ajax的请求时ajaxStart都会执行元素注册的事件处理函数。这和Ext的事件有点相似。但是它不是全局的。
jQuery.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","), function(i, o) {
	jQuery.fn[o] = function(f) {// f:function
		return this.bind(o, f);
	};
上面的代码是为jquery对象注册了ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend这几种ajax的事件方法，在jquery.ajax中不同的时刻都会触发这些事件。当然我们也可以采用s.global=false来设定不触发这些事件。
因为这是全局的，个人认为其设计的目的就是为了在这些时候能以某种形式来告诉用户ajax的进行的状态。如在ajaxstart的时候，我们可能通过一个topest的div层（加上遮罩的效果）的元素注册一个ajaxstart事件的处理方法。该方法就是显示这个层和显示“你的数据正在提交。。。”这个的提示。这是这6种事件的最佳用法了。
如果进行私有处理，那么要在事件的处理函数中进行判断。因为每个事件处理函数的第二参数是jquery.ajax(s)的s参数。我们可以在这个参数中做私有的标识，如eventType:xxx。每类不同的请求有不同的eventType值。在事件处理函数再根据这个eventType==xxx进行判断，从而进行私有的处理。如果有大量的这样的私有处理也是会影响ajax的效率的。
setRequestHeader
⑥处是创建一个xhr对象并通过open来创建一个连接（socket）。
⑦处是设定请求的头部(setRequestHeader)。如果data的存在的话，那就得设定Content-Type，便于服务器按一定的规则来解码。可以看出post的方式通过data传递数据要安全一点。
那么服务器如果区别这个请求是ajax呢？因为同步和异步ajax的请求的头文件是一样的。我们如果通过X-Requested-With"="XMLHttpRequest”来标识这个请求是ajax的请求。如果服务器硬是要区分的话，就可以通过获取该头部来判断。
在头部的定义中，还可能通过Accept来指定接受的数据的类型，如application/xml, text/xml", "text/html", "text/javascript, 等等。
头部还有一个If-Modified-Since的属性用来提高效率的。它和”Last-Modified配合起来使用。在浏览器第一次请求某一个URL时，服务器端的返回状态会是200，内容是你请求的资源，同时有一个Last-Modified的属性标记此文件在服务期端最后被修改的时间，格式类似这样：Last-Modified: Fri, 12 May 2006 18:53:33 GMT 
客户端第二次请求此URL时，根据 HTTP 协议的规定，浏览器会向服务器传送 If-Modified-Since 报头，询问该时间之后文件是否有被修改过：  If-Modified-Since: Fri, 12 May 2006 18:53:33 GMT    如果服务器端的资源没有变化，则自动返回 HTTP 304 （Not Changed.）状态码，内容为空，这样就节省了传输数据量。
当服务器端代码发生改变或者重启服务器时，则重新发出资源，返回和第一次请求时类似。从而保证不向客户端重复发出资源，也保证当服务器有变化时，客户端能够得到最新的资源。
拦截处理
⑧处是一个send之前的拦截处理，可以通过s. beforeSend(xhr, s)函数的形式传入拦截函数。保证在发送之前确保满足某些条件。在取得返回数据的时候，也可以通过s.dataFilter(data, type);形式来拦截处理data。不过这里主要的作用对data进一步的筛选。
onreadystatechange
⑨处是onreadystatechange的回调处理。这里采用是poll的形式进行处理。它把返回的状态分成status:tiemout--&gt;error--&gt;notmodified--&gt;success—&gt;parsererror这几种。如果status == "success"那么分析这些数据之后再进行last-modified相关的处理。为了不取回没有修改过数据。
分析数据的代码如下：
//处理请求返回的数据
	httpData : function(xhr, type, s) {
		var ct = xhr.getResponseHeader("content-type"), 
		  xml = type == "xml"	|| !type &amp;&amp; ct &amp;&amp; ct.indexOf("xml") &gt;= 0, 
		   data = xml? xhr.responseXML	: xhr.responseText;
		if (xml &amp;&amp; data.documentElement.tagName == "parsererror")
			throw "parsererror";
		//允许一个pre-filtering函数清洁repsonse		
		if (s &amp;&amp; s.dataFilter)
			data = s.dataFilter(data, type);
				//script时，就运行
		if (type == "script")	jQuery.globalEval(data);
		//json，生成json对象。
		if (type == "json")		data = eval("(" + data + ")");
		return data;
	},
如果返回的content-type是xml,html,text等都返回。对script执行jQuery.globalEval来执行它。对于Json类型，通过eval来生成返回的json对象。
// 在全局的范围eval 代码，也就是在&lt;head&gt;&lt;/head&gt;中
globalEval : function(data) {
	data = jQuery.trim(data);
		if (data) {
// Inspired by code by Andrea Giammarchi
// http://webreflection.blogspot.com/2007/08/
//global-scope-evaluation-and-dom.html
	var head = document.getElementsByTagName("head")[0]
						|| document.documentElement,
		script = document.createElement("script");
	script.type = "text/javascript";
	if (jQuery.browser.msie)	script.text = data;
	else	script.appendChild(document.createTextNode(data));

	// Use insertBefore instead of appendChild to circumvent an IE6
	// bug. This arises when a base node is used (#2709).
		head.insertBefore(script, head.firstChild);
		head.removeChild(script);
			}		},
				
</pre>
<p>&nbsp;</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://jljlpch.javaeye.com/blog/233252#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 27 Aug 2008 16:50:49 +0800</pubDate>
        <link>http://jljlpch.javaeye.com/blog/233252</link>
        <guid>http://jljlpch.javaeye.com/blog/233252</guid>
      </item>
      <item>
        <title>jquery event domready</title>
        <author>jljlpch</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jljlpch.javaeye.com">jljlpch</a>&nbsp;
          链接：<a href="http://jljlpch.javaeye.com/blog/232935" style="color:red;">http://jljlpch.javaeye.com/blog/232935</a>&nbsp;
          发表时间: 2008年08月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">6.3 domReady的处理</pre>
<pre name="code" class="java">                             prk/彭仁夔    08-08-26
	Domready是每个lib都要实现的函数，因为dom还没有完全ready，那么对于对于dom元素的操作可能出错，因为dom树中可能还没有Load这个元素。为了保障不出现这样的错误，就出现地domready。对于每种浏览器Domready都有着自己不同的判断。
Jquery的domready的实现和其它的lib的实现没有什么区别。
	//dom ready时执行 fn
	ready : function(fn) {			
			bindReady();//注册监听			
			if (jQuery.isReady)//ready就运行				
				fn.call(document, jQuery);			
			else
				// 增加这个函数到queue中。可见支持无数的ready的调用。
				jQuery.readyList.push(function() {
					return fn.call(this, jQuery);
				});
			return this;
		}
我们通过$(fn)的方法就是在调用这个方法。它首先通过bindReady()来注册监听dom是否已经loaded。如果已经loaded就运行fn。如果没有就把fn存放在readyList中。对于多个$(fn)，把它们各自的fn参数保存在公共的jQuery. readyList的公共集合中。待到dom loaed之后统一运行。对于dom 已经loaded，就可以分别去运行fn。
var readyBound = false;

function bindReady() {
	if (readyBound)
		return;
	readyBound = true;

	// Mozilla, Opera, webkit nightlies 支持DOMContentLoaded事件	
if (document.addEventListener &amp;&amp; !jQuery.browser.opera)
		//当DOMContentLoaded事件触发时就运行jQuery.ready
document.addEventListener("DOMContentLoaded", jQuery.ready, false);

	//IE或不是frame的window
	if (jQuery.browser.msie &amp;&amp; window == top)
		(function() {
			if (jQuery.isReady)
				return;
			try {
				// 在ondocumentready之前，一直都会抛出异常				
				// http://javascript.nwbox.com/IEContentLoaded/
				document.documentElement.doScroll("left");
			} catch (error) {
				//一直运行bindReady()(=arguments.callee)
				setTimeout(arguments.callee, 0);
				return;
			}			
			jQuery.ready();//documentready就运行jQuery.ready
		})();

	if (jQuery.browser.opera)
		document.addEventListener("DOMContentLoaded", function() {
			if (jQuery.isReady)
				return;
				//只有styleSheets完全enable时，才是完全的load,其实还有pic
		for (var i = 0;i &lt; document.styleSheets.length; i++)
		  if (document.styleSheets[i].disabled) {//通过styleSheets来判断
					setTimeout(arguments.callee, 0);
					return;
				}			
				jQuery.ready();
			}, false);

	if (jQuery.browser.safari) {
		var numStyles;
		(function() {
			if (jQuery.isReady)
				return;
				//首先得得到readyState=loaded或=complete
			if (document.readyState != "loaded"
					&amp;&amp; document.readyState != "complete") {
				setTimeout(arguments.callee, 0);
				return;
			}
			//取得style的length,比较它们之间的长度，看看是不是完成loaded
			if (numStyles === undefined)
				numStyles = jQuery("style, 
link[rel=stylesheet]").length;
			if (document.styleSheets.length != numStyles) {
				setTimeout(arguments.callee, 0);
				return;
			}			
			jQuery.ready();
		})();
	}

	//最后只能依赖于window.load.
	jQuery.event.add(window, "load", jQuery.ready);
}
这段代码看起来很多，其实就是采用setTimeout(arguments.callee, 0);反复来运行bindReady。如果其得到dom ready的条件满足的话，就执行jQuery.ready()来执行通过$(fn)注册的fn函数。对于每种浏览器，这个满足的条件是不一样。上面的代码就是针对于几种常用的浏览器分别做了各自的处理。
isReady : false,
	readyList : [],
	// Handle when the DOM is ready
		ready : function() {			
			if (!jQuery.isReady) {		
				jQuery.isReady = true;				
				if (jQuery.readyList) {					
					jQuery.each(jQuery.readyList, function() {
						this.call(document);
					});				
					jQuery.readyList = null;
				}				
				jQuery(document).triggerHandler("ready");
			}
		}
	});
当运行到jQuery.ready()的时候就说明dom已经完全的Loaded，那么现在就应该执行保存在jQuery.readyList中的fn。jQuery.ready()就是完成这个工作。
</pre>
<p>&nbsp;</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://jljlpch.javaeye.com/blog/232935#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 26 Aug 2008 17:39:18 +0800</pubDate>
        <link>http://jljlpch.javaeye.com/blog/232935</link>
        <guid>http://jljlpch.javaeye.com/blog/232935</guid>
      </item>
      <item>
        <title>jquery event trigger 分析</title>
        <author>jljlpch</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jljlpch.javaeye.com">jljlpch</a>&nbsp;
          链接：<a href="http://jljlpch.javaeye.com/blog/232934" style="color:red;">http://jljlpch.javaeye.com/blog/232934</a>&nbsp;
          发表时间: 2008年08月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">6.2.2 trigger</pre>
<pre name="code" class="java">                    prk/彭仁夔  08-08-26
注册了事件，如onclick。那么当用户点击这个元素时，就会自动触发这个事件的已经注册的事件处理函数。但是我们有的时候要采用程序来模拟事件的触发就得采用强迫触发某个事件。在IE中我们可以采用.fireEvent()来实现。如：&lt;form onsubmit="a()" &gt;中，如果button的form.submit()的方式提交表单，是不会主动触发onsumbit事件的，如果必须的话，就要在submit前$(“:form”)[0].fireEvent("onsubmit”,)，这样就会触发该事件。
在mozilla中有三个步骤：    var   evt   =   document.createEvent('HTMLEvents');
 evt.initEvent('change',true,true);    t.dispatchEvent(  evt );
在prototype是采用这样的方式来实现的。那么jquery中呢，它的实现方式有一点不一样。
trigger : function(type, data, fn) {
return this.each(function() {
		jQuery.event.trigger(type, data, this, true, fn);
			});	},
Trigger有三个参数，data参数是为了注册的事件函数提供了实传。如果data[0]中preventDefault存在，data[0]就可以做为用户自定义的包裹事件的空间。Fn是可以为事件提供一个即时即用的事件处理方法。也就是在没有注册事件的情况下也可以通过传入处理函数来处理事件。如果已经注册了，那就是在原来的事件处理函数之后执行。
  	//这个方法将会触发指定的事件类型上所有绑定的处理函数。但不会执行浏览器默认动作.
triggerHandler : function(type, data, fn) {
return this[0]&amp;&amp; jQuery.event.trigger(type,data,this[0],false,fn);
	},
triggerHandle通过把jQuery.event.trigger的donative参数设为false，来阻止执行浏览器默处理方法。它与trigger不现的一点，还在于它只是处理jquery对象的第一个元素。
上面两个方法都调用了jQuery.event.trigger来完成任务：
trigger : function(type, data, elem, donative, extra) {
	data = jQuery.makeArray(data);//data可以为{xx:yy}
    //支持getData!这样的形式，exclusive = true表现会对add的注册的
	//事件的所有函数进行命名空间的分种类的来执行。
if (type.indexOf("!") &gt;= 0) {                         ①
		type = type.slice(0, -1);var exclusive = true;
		}
if (!elem) {// 处理全局的fire事件                       ②
	if (this.global[type])
		jQuery.each(jQuery.cache, function() {
		  // 从cache中找到所有注册该事件的元素，触发改事件的处理函数
			if (this.events &amp;&amp; this.events[type])
				jQuery.event.trigger(type, data, this.handle.elem);
			});
	} else {// 处理单个元素事件的fire事件                    ③
	 if (elem.nodeType == 3 || elem.nodeType == 8)	return undefined;
      var val, ret, fn = jQuery.isFunction(elem[type] || null),
	 // 如果data参数传进入的不是浏览器的event对象的话，event变量为true.
	//如果data参数本身是娄组，那么第一个元素不是浏览器的event对象时为true.
	//对于event为true。即没有event传进入，先构建一个伪造的event对象存在data[0]。
	event = !data[0] || !data[0].preventDefault;
    	// 在没有传入event对象的情况下，构建伪造event对象。
	if (event) {//存到数组中的第一个                          ④
		data.unshift( { type : type,target : elem,
	         preventDefault : function() {},stopPropagation : 
function() {}, timeStamp : now()	});
	   data[0][expando] = true; // 不需要修正伪造的event对象
		}
	 data[0].type = type; //防止事件名出错
	//表现会进行事件注册函数的分类（命名空间）执行。不是所有的。
	 if (exclusive) data[0].exclusive = true;

	//与prototype等传统的处理方式不一样，没有采用fireEvent来
	//来fire通过注册到浏览器事件中的事件处理方法。
	//这里分了三步，先fire通过jQuery.event.add来注册的事件，这个事件
	//有可能是自定义的事件（没有注册到浏览器事件中）。
	//第二步是fire通过elem.onclick方式注册的事件的本地处理函数
     //第三步是fire默认的事件处理方式（在本地的onclick的方式注册
	 //不存在的情况下）。	
	
// 这里是触发通过jQuery.event.add来注册的事件，
	  var handle = jQuery.data(elem, "handle");            ⑤
	  if (handle)val = handle.apply(elem, data); //这里data分成多个参数
	//处理触发通过elem.onfoo=function()这样的注册本地处理方法，
	//但是是对于links 's .click()不触发,这个不会执行通过addEvent
	//方式注册的事件处理方式。			
	if ((!fn || (jQuery.nodeName(elem, 'a') &amp;&amp; type == "click")) ⑥
		&amp;&amp; elem["on"+ type]&amp;&amp; elem["on"+type].apply(elem,data) === false)
	  val = false;
//额外的函数参数的开始几个是通过data给定的。这里会把伪造加上的event给去掉。
//它的最后一个参数是一系列的事件处理函数返回的结果，一般为bool值
//这个函数可以根据这个结果来处理一个扫尾的工作。
	if (event)	data.shift();
// 处理触发extra给定的函数处理。
	if (extra &amp;&amp; jQuery.isFunction(extra)) {                     ⑦
		 ret = extra.apply(elem, val == null ? data : data.concat(val));
		 //如果这个函数有返回值，那么trigger的返回值就是它的返回值
		 //没有的话就是串连的事件处理函数的最后一个返回值。一般为bool
		if (ret !== undefined)	val = ret;
	 }
	// 触发默认本地事件方法，它是在没有如.onclick注册事件
	//加上前面的执行事件处理函数返回值都不为false的情况下，才会执行。
	//它还可以通donative来控制是否执行。
	//如form中可以采用this.submit()来提交form.
	if (fn &amp;&amp; donative !== false &amp;&amp; val !== false          ⑧
				&amp;&amp; !(jQuery.nodeName(elem, 'a') &amp;&amp; type == "click")) {
		this.triggered = true;
		try {elem[type]();	//对于一些hidden的元素，IE会报错
			} catch (e) {}
		}
	this.triggered = false;
	}
return val;
},
Jquery的fire事件的方法与prototype中实现是完全不一样的。Ext、YUI没有提供强迫触发事件的方法。对于一般的思维，程序来触发浏览器的事件就应该采用fireEvent或dispatchEvent方法来运行。
但是jquery采用一种不同的方法。对于通过jquery.event.add来注册的事件（不管是自定义的还是注册到浏览器事件），它保存在一个与元素及事件名相对应的cache中。在浏览器的触发中，这个是没有什么作用。但是它是为了通过等程序来强迫触发时，从cache中取到对应的事件处理函数。这个时候就抛开了浏览器的事件。在这里还可以执行一些自定义的事件函数。如⑤处。
对于通过html的标签中如click或elem.onclick=function(){}形式注册的事件函数。在⑥处它采用执行元素的如onclick形式的回调函数就可以。通过这种dom0的方式只能注册一个函数。
有的时候，如果没有onclick这样的事件处理函数，浏览器会执行默认的处理函数。如form.submit()。⑧处可以看出对于这样的默认的事件处理，还可以通过参数donative来控制。
程序手动强迫触发事件，有一点问题就是event是怎么生成，就是没有浏览器生成event传入到函数中。Prototype采用了是新生成的dataavailable的事件。这样的事件也没有什么作用。Jquery也采用fake的方式伪造一个一个事件，如④，它比prototype的事件好处在于它能通过trigger的函数的参数来传入需要的event。Prototype则不能。
通过上面的分析，隐隐可以看出Jquery是通过模拟浏览器的触发事件的执行过程来构建这个trigger的函数的。先执行dom1方式（addEvent）注册的事件，再执行dom0方式注册的事件，最后看看要不要执行默认的事件处理。
在⑦处，我们可以看出trigger还可能通过传入回调函数和参数来完成对执行的事件处理函数的结果进行判断处理，形成新结果通过trigger的函数返回。这在有的时候是很有用的。
除了这些，它还能对于事件的处理函数进行分类（namespace），可以在合适的时候调用事件的不同分类的的处理函数（通过jquery.event.add来注册）。这个分类的处理在handle实现。
	handle : function(event) {
		// 返回 undefined or false
		var val, ret, namespace, all, handlers;
       //修改了传入的参数，这里是引用。
		event = arguments[0] = jQuery.event.fix(event || window.event);
		// 命名空间处理
		namespace = event.type.split(".");
		event.type = namespace[0];
		namespace = namespace[1];
		// all = true 表明任何 handler,namespace不存在，同时
		//event.exclusive不存在或为假时，all=true.
		all = !namespace &amp;&amp; !event.exclusive;
		// 找到元素的events中缓存的事件名的处理函数列表
		handlers = (jQuery.data(this, "events") || {})[event.type];
		for (var j in handlers) {// 每个处理函数执行
			var handler = handlers[j];
			// Filter the functions by class
			if (all || handler.type == namespace) {
				// 传入引用，为了之后删除它们
				event.handler = handler;
				event.data = handler.data;//add的时候加上的
				ret = handler.apply(this, arguments);// 执行事件处理函数
			    if (val !== false)
				   val = ret;// 只要有一个处理函数返回false，本函数就返回false.
				if (ret === false) {// 不执行浏览器默认的动作
					event.preventDefault();
					event.stopPropagation();
				}
			}
		}
		return val;	},
handle的主要功能是就是分类且有序地执行事件的所有的注册的处理函数。
</pre>
<p>&nbsp;</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://jljlpch.javaeye.com/blog/232934#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 26 Aug 2008 17:37:50 +0800</pubDate>
        <link>http://jljlpch.javaeye.com/blog/232934</link>
        <guid>http://jljlpch.javaeye.com/blog/232934</guid>
      </item>
      <item>
        <title>jquery event addEvent 分析</title>
        <author>jljlpch</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jljlpch.javaeye.com">jljlpch</a>&nbsp;
          链接：<a href="http://jljlpch.javaeye.com/blog/232932" style="color:red;">http://jljlpch.javaeye.com/blog/232932</a>&nbsp;
          发表时间: 2008年08月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">6.2 事件的处理</pre>
<pre name="code" class="java">                            prk/彭仁夔   08-08-26
Jquery提供了一些来进行regist,remove,fire事件的方法。
6.2.1 Register
对于注册事件，jquery提供了bind、one、toggle、hover四种注册事件的方法， bind是最基本的方法。One是注册只运行一次的方法，toggle注册交替运行的方法。Hover是注册鼠标浮过的方法。
bind : function(type, data, fn) {
	return type == "unload" ? this.one(type, data, fn) : this
		.each(function() {// fn || data, fn &amp;&amp; data实现了data参数可有可无
					jQuery.event.add(this, type, fn || data, fn &amp;&amp; data);
				});	},
Bind中对于unload的事件，只能运行一次，其它的就采用默认的注册方式。
// 为每一个匹配元素的特定事件（像click）绑定一个一次性的事件处理函数。
// 在每个对象上，这个事件处理函数只会被执行一次。其他规则与bind()函数相同。
// 这个事件处理函数会接收到一个事件对象，可以通过它来阻止（浏览器）默认的行为。
// 如果既想取消默认的行为，又想阻止事件起泡，这个事件处理函数必须返回false。
	one : function(type, data, fn) {
	  var one = jQuery.event.proxy(fn || data, function(event) {
			jQuery(this).unbind(event, one);
		    return (fn || data).apply(this, arguments);/this-&gt;当前的元素
				});
			return this.each(function() {
				jQuery.event.add(this, type, one, fn &amp;&amp; data);
			});
		},
One与bind基本上差不多，不同的在调用jQuery.event.add时，把注册的事件处理的函数做了一个小小的调整。One调用了jQuery.event.proxy进行了代理传入的事件处理函数。在事件触发调用这个代理的函数时，先把事件从cache中删除，再执行注册的事件函数。这里就是闭包的应用，通过闭包得到fn注册的事件函数的引用。
//一个模仿悬停事件（鼠标移动到一个对象上面及移出这个对象）的方法。
//这是一个自定义的方法，它为频繁使用的任务提供了一种“保持在其中”的状态。
 //当鼠标移动到一个匹配的元素上面时，会触发指定的第一个函数。当鼠标移出这个元素时，
/会触发指定的第二个函数。而且，会伴随着对鼠标是否仍然处在特定元素中的检测（例如，处在div中的图像），
  //如果是，则会继续保持“悬停”状态，而不触发移出事件（修正了使用mouseout事件的一个常见错误）。
		hover : function(fnOver, fnOut) {
			return this.bind('mouseenter', fnOver).bind('mouseleave', fnOut);
		},
Hover则是建立在bind的基础之上。
//每次点击后依次调用函数。
toggle : function(fn) {		
var args = arguments, i = 1;
while (i &lt; args.length)//每个函数分配GUID
		jQuery.event.proxy(fn, args[i++]);//修改后的还在args中
return this.click(jQuery.event.proxy(fn, function(event) {//分配GUID			this.lastToggle = (this.lastToggle || 0) % i;//上一个函数				event.preventDefault();//阻止缺省动作
		//执行参数中的第几个函数，apply可以采用array-like的参数
		return args[this.lastToggle++].apply(this,arguments)||false;
	}));
	},
Toggle中参数可以是多个fn。先把它们代码生成UUID。之后调用click的方法来注册再次进行代理的callback。这个函数在事件触发时运行，它先计算上一次是执行了参数中的那个函数。之后阻止缺省动作。之后找到下一个函数运行。
//为jquery对象增加常用的事件方法
jQuery.each(
	("blur,focus,load,resize,scroll,unload,click,dblclick,"
	+ "mousedown,mouseup,mousemove,mouseover,mouseout,change,select," 
+ "submit,keydown,keypress,keyup,error").split(","), 
function(i, name) {jQuery.fn[name] = function(fn) {
					return fn ? this.bind(name, fn) : this.trigger(name);
				};});
Jquery增加了一个常用的事件处理方法，包含上面调用的click。这里可以看出这里还是调用bind进行注册。当然这里还可以通过程序实现去触发事件。

上面的众多方法都是注册事件，其最终都落在jQuery.event.add();来完成注册的功能。如果我们采用Dom0或DOM1的事件方法，我们会采用elem.onclick=function(){}来为元素的某一种事件来注册处理函数。这个最大的缺点就是每个一个事件只是一个处理函数。在dom1的方式中有改进，我们可以采用elem.addEventListener(type, handle, false)为元素的事件注册多个处理函数。
这样的处理方式还不是很完美，如果我们只这个事件运行一次就有点麻烦了。我们要在事件的处理函数中最后进行elem.removeEventListener来取消事件的监听。这样做可能会有事务上的问题。如果第一个事件处理函数在没有取消事件监听之前，就再次触发了怎么办？
还有采用浏览器的方式，它不支持自定义事件的注册和处理，还不能为多个事件注册同一个处理函数。
jQuery.event = {// add 事件到一个元素上。
add : function(elem, types, handler, data) {
if (elem.nodeType == 3 || elem.nodeType == 8) return;// 空白节点或注释
	// IE不能传入window,先复制一下。
if (jQuery.browser.msie &amp;&amp; elem.setInterval) elem = window;
// 为handler分配一个全局唯一的Id
if (!handler.guid)	handler.guid = this.guid++;
// 把data附到handler.data中
if (data != undefined) {                                             ①
var fn = handler;
handler =this.proxy(fn,function(){return fn.apply(this,arguments);});
handler.data = data;
	}
// 初始化元素的events。如果没有取到events中值，就初始化data: {}       ②
var events =jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),
// 如果没有取到handle中值，就初始化data: function() {....}         ③
handle = jQuery.data(elem, "handle")|| jQuery.data(elem, "handle",
function() {//处理一个触发器的第二个事件和当page已经unload之后调用一个事件。
		if (typeof jQuery != "undefined"&amp;&amp; !jQuery.event.triggered)
			return jQuery.event.handle.apply(//callee.elem=handle.elem
		           arguments.callee.elem, arguments);
			});
// 增加elem做为handle属性，防止IE由于没有本地Event而内存泄露。
handle.elem = elem;
// 处理采用空格分隔多个事件名，如jQuery(...).bind("mouseover mouseout", fn);
jQuery.each(types.split(/\s+/), function(index, type) {       ④
	// 命名空间的事件，一般不会用到。
var parts = type.split(".");type = parts[0];handler.type = parts[1];
	// 捆绑到本元素type事件的所有处理函数
var handlers = events[type];                                         ⑤
if (!handlers) {// 没有找到处理函数列表就初始化事件队列
		handlers = events[type] = {};
	// 如果type不是ready，或ready的setup执行返回false                 ⑥
if (!jQuery.event.special[type]|| jQuery.event.special[type].setup
		.call(elem, data) === false) {// 调用系统的事件函数来注册事件
if(elem.addEventListener)elem.addEventListener(type,handle,false);
else if (elem.attachEvent)elem.attachEvent("on" + type, handle);
		   }
}
// 把处理器的id和handler形式属性对的形式保存在handlers列表中，
// 也存在events[type][handler.guid]中。
handlers[handler.guid] = handler;                                   ⑦
// 全局缓存这个事件的使用标识
jQuery.event.global[type] = true;
});

	elem = null; // 防止IE内存泄露。
	},
	guid : 1,
	global : {},
jQuery.event.add通过jQuery.data把事件相关的事件名和处理函数有机有序地组合起存放在jQuery.cache中与该元素对应的空间里。我们就一个例子分析一下add的过程中：假如我们招待下面jQuery(e1).bind("mouseover mouseout", fn0);jQuery(e1).bind("mouseover mouseout", fn1)的语句。
在jQuery(e1).bind("mouseover mouseout", fn0);时，②③都不可能从cache取到数，先初始化。此时的cache:{e1_uuid:{events:{},handle:fn}}。接着在⑤会为mouseover mouseout名初始化。此时的cache: {e1_uuid:{events:{ mouseover:{}, mouseout:{}},handle:fn}}。在⑥处向浏览器的事件中注册处理函数。接着⑦会把处理函数到事件名中。此时的cache: {e1_uuid:{events:{mouseover:{fn0_uuid:fn0},mouseout:{ fn0_uuid:fn0}},handle:fn}}。这里可以看出为采用proxy为函数生成uuid的作用了。
在jQuery(e1).bind("mouseover mouseout", fn1)时，②③都从cache取到数据{e1_uuid:{events:{mouseover:{fn0_uuid:fn0},mouseout:{ fn0_uuid:fn0}},接着在⑤取到mouseover:{fn0_uuid:fn0},mouseout:{ fn0_uuid:fn0}的引用。接着⑦会把处理函数注册到事件名中。此时的cache: {e1_uuid:{events:{mouseover:{fn0_uuid:fn0, fn1_uuid:fn1,},mouseout:{ fn0_uuid:fn0, fn1_uuid:fn1}},handle:fn}}。
jQuery.event.add很重要的任务就是把注册的事件函数有序地存放起来。以便remove和fire事件的函数能找到。
//{elem_uuid_1:{events:{mouseover:{fn_uuid:fn1,fn_uuid1:fn2},
				//mouseout:{fn_uuid:fn1,fn_uuid1:fn2}},handle:fn}}

</pre>
<p>&nbsp;</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://jljlpch.javaeye.com/blog/232932#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 26 Aug 2008 17:36:47 +0800</pubDate>
        <link>http://jljlpch.javaeye.com/blog/232932</link>
        <guid>http://jljlpch.javaeye.com/blog/232932</guid>
      </item>
      <item>
        <title>jquery event 封装的源源分析</title>
        <author>jljlpch</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jljlpch.javaeye.com">jljlpch</a>&nbsp;
          链接：<a href="http://jljlpch.javaeye.com/blog/232931" style="color:red;">http://jljlpch.javaeye.com/blog/232931</a>&nbsp;
          发表时间: 2008年08月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">6.Event分析</pre>
<pre name="code" class="java">                                      prk/彭仁夔   08-08-26
对于javascript事件扩展，所有的lib都差不多。和jquery和prototype,yui和Ext，其要解决的首要问题是兼容性，所有lib都会对event进行包裹，统一其属性解决其兼容性。对于事件的操作无非是addEvent,fireEvent,removeEvent这三个事件方法。一般lib都会对浏览器的提供的函数做一些扩展，解决兼容性内存泄漏等问题。第三个问题就是如何得到domReady的状态。
6.1 event的包裹
浏览器的事件兼容性是一个令人头疼的问题。IE的event在是在全局的window下，而mozilla的event是事件源参数传入到回调函数中。还有很多的事件处理方式也一样。
Jquery提供了一个 event的包裹，这个相对于其它的lib提供的有点简单，但是足够使用。
//对事件进行包裹。
	fix : function(event) {
		if (event[expando] == true) return event;//表明事件已经包裹过
		//保存原始event,同时clone一个。
		var originalEvent = event;                               ①
		event = {	originalEvent : originalEvent};
		for (var i = this.props.length, prop;i;) {
			prop = this.props[--i];
			event[prop] = originalEvent[prop];
		}		
		event[expando] = true;		
		//加上preventDefault and stopPropagation，在clone不会运行
		event.preventDefault = function() {                   ②
			// 在原始事件上运行
			if (originalEvent.preventDefault)
				originalEvent.preventDefault();
			originalEvent.returnValue = false;
		};
		event.stopPropagation = function() {
			// 在原始事件上运行
			if (originalEvent.stopPropagation)
				originalEvent.stopPropagation();
			originalEvent.cancelBubble = true;
		};
		// 修正 timeStamp
		event.timeStamp = event.timeStamp || now();
		// 修正target
		if (!event.target)                                       ③
			event.target = event.srcElement || document; 			
		if (event.target.nodeType == 3)//文本节点是父节点。
			event.target = event.target.parentNode;
		// relatedTarget
		if (!event.relatedTarget &amp;&amp; event.fromElement)      ④
			event.relatedTarget = event.fromElement == event.target
					? event.toElement	: event.fromElement;
		// Calculate pageX/Y if missing and clientX/Y available
		if (event.pageX == null &amp;&amp; event.clientX != null) {  ⑥
			var doc = document.documentElement, body = document.body;
		  event.pageX = event.clientX
				+ (doc &amp;&amp; doc.scrollLeft || body &amp;&amp; body.scrollLeft || 0)
					- (doc.clientLeft || 0);
			event.pageY = event.clientY
				+ (doc &amp;&amp; doc.scrollTop || body &amp;&amp; body.scrollTop || 0)
					- (doc.clientTop || 0);
		}

		// Add which for key events
	if (!event.which	&amp;&amp; ((event.charCode || event.charCode === 0) ⑦
						? event.charCode	: event.keyCode))
			event.which = event.charCode || event.keyCode;

	// Add metaKey to non-Mac browsers 
		if (!event.metaKey &amp;&amp; event.ctrlKey)                        ⑧
			event.metaKey = event.ctrlKey;
	// Add which for click: 1 == left; 2 == middle; 3 == right
	// Note: button is not normalized, so don't use it
		if (!event.which &amp;&amp; event.button)                          ⑨
			event.which = (event.button &amp; 1 ? 1 : (event.button &amp; 2
					? 3	: (event.button &amp; 4 ? 2 : 0)));
		return event;
	},
上面的代码①处保留原始事件的引用，同时clone原始事件。在这个clone的事件上进行包裹。②处在原始事件上运行preventDefault 和 stopPropagation两个方法达到是否阻止默认的事件动作发生和是否停止冒泡事件事件向上传递。
③处是修正target个，IE中采用srcElement，同时对于文本节点事件，应该把target传到其父节点。
④处relatedTarget只是对于mouseout、mouseover有用。在IE中分成了to和from两个Target变量，在mozilla中没有分开。为了保证兼容，采用relatedTarget统一起来。
⑥处是进行event的坐标位置。这个是相对于page。如果页面可以scroll，则要在其client上加上scroll。在IE中还应该减去默认的2px的body的边框。
⑦处是把键盘事件的按键统一到event.which的属性上。Ext中的实现ev.charCode || ev.keyCode || 0; ⑨则是把鼠标事件的按键统一把event.which上。charCode、ev.keyCode一个是字符的按键，一个不是字符的按键。⑨处采用&amp;的方式来进行兼容性的处理。 Ext 通过下面三行解决兼容问题。
  var btnMap = Ext.isIE ? {1:0,4:1,2:2} : (Ext.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2}); this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
①②③④⑤⑥⑦⑧⑨⑩
</pre>
<p>&nbsp;</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://jljlpch.javaeye.com/blog/232931#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 26 Aug 2008 17:35:23 +0800</pubDate>
        <link>http://jljlpch.javaeye.com/blog/232931</link>
        <guid>http://jljlpch.javaeye.com/blog/232931</guid>
      </item>
      <item>
        <title>jquery position</title>
        <author>jljlpch</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jljlpch.javaeye.com">jljlpch</a>&nbsp;
          链接：<a href="http://jljlpch.javaeye.com/blog/232480" style="color:red;">http://jljlpch.javaeye.com/blog/232480</a>&nbsp;
          发表时间: 2008年08月25日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">5.2.3 position     </pre>
<pre name="code" class="java">                               prk/彭仁夔   08-08-25
在给元素定位之前，我们首先要了解一些CSS定位相关的知识。
在CSS中关于定位的内容是：position:relative | absolute | static | fixed 。static 没有特别的设定，遵循基本的定位规定，不能通过z-index进行层次分级。relative 不脱离文档流，参考自身静态位置通过 top,bottom,left,right 定位，并且可以通过z-index进行层次分级。absolute 脱离文档流，通过 top,bottom,left,right 定位。选取其最近的父级定位元素，当父级 position 为 static 时，absolute元素将以body坐标原点进行定位，可以通过z-index进行层次分级。
fixed 固定定位，这里他所固定的对像是可视窗口而并非是body或是父级元素。可通过z-index进行层次分级。CSS中定位的层叠分级：z-index: auto | namber
relative | absolute | static | fixed这四种定位的方式不一样，我们要找到元素的位置的方法也会随之不一样。
Dom元素提供了三种方式来定位元素：offset，scroll，Client，
 
图 转自（http://www.cnblogs.com/believe3301/archive/2008/07/19/1246806.html）
Dom元素对于offset提供了offsetParent、offsetTop、offsetLeft、offsetWidth、offsetHeight五个方法来定位于元素的相对位置。
offsetParent是指当前元素的相对定位的元素。在IE和FF中定义和解释不一样。在IE中定义为获取定义对象 offsetTop 和 offsetLeft 属性的容器对象的引用。大多数时候offsetParent返回body元素。在IE5中，td的offsetParent是table。可以看出IE中的相对定位与绝对定位的区别不大。都是相对于最上层的元素来定位。在FF中获取文档层次中最近的元素。如果这个元素没有定位，那么就根元素。
offsetParent、parentNode（IE:parentElement）都是指元素的父节点。它们的针对的目标是不一样，功能也不一样。parentNode就是取文档层次中包含该节点的最近节点（直接的父节点）。在FF中对于Attr, Document, DocumentFragment, Entity,和Notation这些父节点，其 parentNode返回null。还有如果没有附加到文档树的元素也是返回null。
   offsetParent是指可视的父节点。如 &lt;body&gt;&lt;form&gt;&lt;input type=’’’text’ id=’AA’/&gt;&lt;/form&gt;&lt;/body&gt;。AA的offsetParent是body，而parentNode则是form。在IE中一般都是body。
offsetLeft和offsetTop是指当前元素left或top边到offsetParent的left或top边的距离，包含了当前元素的margin和其offsetParent的padding。不包含offsetParent的border的宽度。
offsetWidth、offsetHeight与offsetLeft、offsetTop的相对offsetParent的方式不一样，它们就是当前元素自身的宽度或高度。它包含border、padding、scrollBar(显示的话)和内容的size(CSS中设定的元素的高度，IE中CSS size指的是包含border的内容大小)。
分析了offset，我们可以发现offsetLeft、offsetTop与CSS中top,left的属性有相通性，offsetLeft、offsetTop只能取值。而我们可以通过CSS中top,left的属性来设定一个元素的相对其它元素的位置（绝对定位，就是相对于body）。

 Dom元素对于scroll提供了scrollWidth、scrollHeigth、scrollTop、scrollLeft。这一组是对于scroll的元素进行操作的。Scroll的Width、Heigth是指元素真实的宽度和高度，它包含被scroll起来的部分。而scrollTop、scrollLeft则是被卷起来的部分的大小。
 Dom元素对于scroll提供了clientWidth、clientHeigth、clientTop、clientLeft。这一组是对于client进行操作的。clientWidth、clientHeigth是元素的内容可视区域的高度或宽度。包含padding，不包含scrollbar 、border、margin。可以看出是元素可视的区域。IE，FF是一样的。clientTop、clientLeft可以看做是topborder或left border的大小。

offsetParent的名字的元素能计算相对位移的父节点，那么对于CSS的定位方式，哪一些是可以计算位移呢，能计算元素和其父节点之间的位移量，首先要其父节点能定位。这个定位就是在CSS中能采用top,left来定其在文档的位置。Body是肯定可以的（0，0）。Body也是元素的终结offsetParent（没有找到就是它了）,absolute、 relative、 fixed都采用可以top,left来定其在文档的位置。也是能计算其位置。而static是不需要top,left来设定其位置， Offset是相对已经定位的元素的位移。元素的offsetParent是其父辈节点中的postiont!= Static的节点。在IE中http://msdn.microsoft.com/zh-cn/library/system.windows.forms.htmlelement.offsetparent(VS.80).aspx，可以看到其不支持fixed的offsetParent。在mozilla中http://developer.mozilla.org/en/DOM/element.offsetParent，可以看出其给出的如果元素没有定位（non-positioned）就是body。
Jquery针对于offsetParent提供了一个改进的方法。它还是在浏览器的offsetParent基础之上多加了一个判断的处理，筛选其有可能会是static的节点。觉得这样做的意义不大。除了table,tr,td之外，浏览器的offsetParent是body的可能性很大。这是一个不确定的。在使用中是要注意的。
//找到this[0]中元素第一个能根据CSS中的top,left能设定位置的父辈节点。
	offsetParent: function() {
		var offsetParent = this[0].offsetParent || document.body;
	while ( offsetParent &amp;&amp; (!/^body|html$/i.test(offsetParent.tagName) 
&amp;&amp; jQuery.css(offsetParent, 'position') == 'static') )
		offsetParent = offsetParent.offsetParent;
		return jQuery(offsetParent);
	}

其实觉得最好的方法还是直接相对于body的来定位。这样的定位是确定的。但是浏览器在计算这个值会有点问题，而且每种浏览器的实现方式不一样，很难兼容。Jquery提供了一个相对于文档的起始位置的offset方法。

//元素相对于文档的起始位置的offset
jQuery.fn.offset = function() {
	var left = 0, top = 0, elem = this[0], results;
	if ( elem ) with ( jQuery.browser ) {
		var parent    = elem.parentNode,    offsetChild  = elem,
		  offsetParent = elem.offsetParent,
		 doc       = elem.ownerDocument,
		 safari2   = safari &amp;&amp; parseInt(version) &lt; 522 
&amp;&amp; !/adobeair/i.test(userAgent),
	   css          = jQuery.curCSS,
	   fixed        = css(elem, "position") == "fixed";

 //在IE中有的元素可以通过getBoundingClientRect来获得