<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>jef</title>
    <description></description>
    <link>http://jef.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>利用table,div实现动态柱状图表</title>
        <author>jef</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jef.javaeye.com">jef</a>&nbsp;
          链接：<a href="http://jef.javaeye.com/blog/166486" style="color:red;">http://jef.javaeye.com/blog/166486</a>&nbsp;
          发表时间: 2008年03月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>想来很有趣，没想到利用table,div,css,javascript也可以实现一个动态的柱状图表。效果还不错，如下图。基本可以应付简单的需要，更重要的是可以做到柱形图的动态显示 呵呵</p><p>&nbsp;</p><p>&nbsp;</p><p><img src="../../../upload/picture/pic/8664/1876fa2b-46e4-3716-b89b-b25e474f7440.jpg" border="0" height="272" align="middle" alt="" width="600" /> </p><p>&nbsp;</p><p>&nbsp;</p><p>用一个table实现柱状图表,table结构如下:</p><pre name="code" class="html">&lt;table&gt;
	&lt;caption&gt;统计分析 (2007-02～2008-02)&lt;/caption&gt;
	&lt;thead&gt;&lt;/thead&gt;
	&lt;tbody&gt;
		&lt;tr style=&quot;height:300px;&quot;&gt;
			&lt;td class=&quot;chartcaption&quot; style=&quot;vertical-align:top;border-right:1px solid #004477;border-bottom:none;&quot;&gt;
				&lt;p style=&quot;padding-top:10px;&quot;&gt;消&lt;/p&gt;&lt;p&gt;费&lt;/p&gt;&lt;p&gt;金&lt;/p&gt;&lt;p&gt;额&lt;/p&gt;&lt;p&gt;(元)&lt;/p&gt;
			&lt;/td&gt;
			&lt;td&gt;&lt;p&gt;&lt;span&gt;12899&lt;/span&gt;&lt;/p&gt;&lt;div id=&quot;firstcolumn&quot; title=&quot;消费金额:12899 元&quot; class=&quot;tdbg&quot; style=&quot;height:80%;&quot;&gt;&lt;/div&gt;&lt;/td&gt;
			&lt;td&gt;&lt;p&gt;&lt;span&gt;9616&lt;/span&gt;&lt;/p&gt;&lt;div title=&quot;消费金额:9616 元&quot; class=&quot;tdbg&quot; style=&quot;height:60%;&quot;&gt;&lt;/div&gt;&lt;/td&gt;
			....
			....
			....
			&lt;td&gt;&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style=&quot;border:none;&quot;&gt;&lt;/td&gt;
			&lt;td style=&quot;border:none;&quot;&gt;07/02&lt;/td&gt;
			....
			....
			....
			&lt;td class=&quot;chartcaption&quot; style=&quot;border:none;&quot;&gt;月份&lt;/td&gt;
		&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;</pre><p>&nbsp;</p><p>代码比较简单，table也只有2行，x轴上下各是一行。设定一下tr或td的border属性就可以画出x轴，y轴。</p><p>柱形图就是在一个td里面有蓝色背景的div~,设定这个div的height属性就可以决定每个柱形图的高度了。</p><p>重要的还是要写一些css代码来控制这个table及其div元素的表现形式。</p><p>&nbsp;</p><p>再说说动态实现部分吧，这个很爽啊。</p><p>其实要控制一个柱形的高度只要给这个div设定一个id，然后再修改这个div的height属性就行了。</p><p>如：</p><pre name="code" class="html">&lt;td&gt;&lt;p&gt;&lt;span&gt;12899&lt;/span&gt;&lt;/p&gt;&lt;div id=&quot;firstcolumn&quot; title=&quot;消费金额:12899 元&quot; class=&quot;tdbg&quot; style=&quot;height:80%;&quot;&gt;&lt;/div&gt;&lt;/td&gt;</pre><p>&nbsp;</p><p>为第一个柱形div标号 id = firstcolumn.</p><p>&nbsp;</p><p>javascript代码修改height属性</p><pre name="code" class="js">&lt;input type=&quot;button&quot; value=&quot;change&quot; onclick=&quot;change()&quot;/&gt;
&lt;script language=&quot;javascript&quot; src=&quot;include/prototype.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
&lt;script&gt;
var times = 0;
function change(){
	add(times);
	times = times+5;
}
function add(time){
	var firstColumn = $('firstcolumn');
	firstColumn.style.height = time+'%';
}
&lt;/script&gt;</pre><p>&nbsp;</p><p>&nbsp;</p><p>现在大功告成 点击change按钮就可改变第一个柱形的高度了～</p><p>实际应用中可以由ajax技术来控制柱形的变化。例如一个带ajax功能的函数每隔一段时间向后台请求一次，获得最新的数据信息之后再做柱形图高度的同步，还不错吧。</p><p>&nbsp;</p><p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://jef.javaeye.com/blog/166486#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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/115' target='_blank'><span style="color:red;font-weight:bold;">JavaEye图灵杯第2届问答大赛开始了！8月4日至8月17日，奖品丰厚！</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>Sat, 01 Mar 2008 19:14:16 +0800</pubDate>
        <link>http://jef.javaeye.com/blog/166486</link>
        <guid>http://jef.javaeye.com/blog/166486</guid>
      </item>
      <item>
        <title>[转]Prototype 1.4.0 源码解读----全文注释版</title>
        <author>jef</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jef.javaeye.com">jef</a>&nbsp;
          链接：<a href="http://jef.javaeye.com/blog/155985" style="color:red;">http://jef.javaeye.com/blog/155985</a>&nbsp;
          发表时间: 2008年01月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          dae739ba<br />AJAX之旅：由prototype_1.4<br />还是决定冠上ajax的头衔，毕竟很多人会用这个关键词搜索。虽然我认为这只是个炒作的概念，不过不得不承认ajax叫起来要方便多了。所以ajax的意思我就不详细解释了。<br />写这个教程的起因很简单：经过一段时间的ajax学习，有一些体会，并且越发认识到ajax技术的强大，所以决定记录下来，顺便也是对自己思路的整理。有关这个教程的后续，请关注http://www.x2design.net<br />前几年，javascript在一般人眼里，功能还很狭窄，所能做的要么是一些简单的表单验证，要么是许多华而不实的网页特效。随着flash的出现，大家已经不像以前那样热衷于js特效。似乎js能做的事情更加少了。但这时候，ajax的概念冒了出来，以gmail为典型代表的ajax应用受到很多人的关注，ajax一下子成为一种很热门的技术，当javascript和xml，和dom模型结合起来，其所能做的事情常常令人匪夷所思，甚至有些功能已经可以和桌面程序相当。<br />好了废话就不多说了，现在就从一个javascript的开发框架prototype_1.3.1（下面简称为prototype）开始。我本来是想先介绍一下javascript的高级应用，但怕水平不够，说的没有条理，所以就结合prototype来说，顺便会提及js的语法使用。dae739ba<br />下面是框架最前面的两段代码：<br />var Prototype = {<br />  Version: '1.3.1',<br />  emptyFunction: function() {}<br />}<br />var Class = {<br />  create: function() {<br />    return function() { <br />      this.initialize.apply(this, arguments);<br />    }<br />  }<br />}<br />首先，让我们来看下面两个语法的区别：<br />var o={};<br />var f=function(){};<br /><br />后面一个很容易理解，它等价于function f(){};定义一个函数f。但前面一个就不常见了：这其实是创建一个对象，在{}中可以指定对象的成员，比如上面的Prototype，就是一个对象，有两个成员，第一个是版本号，第二个是一个空方法（函数）。像这种不用定义类，就能直接创建对象的功能可能只有js能做到。后面一种语法其实还有一个功能，就是定义一个类f。如果你在函数体中用了this，那么this后面的变量就是类的成员。<br />不仅this可以定义类成员，还有一种语法：<br />function c(){<br /> member1:value,<br /> member2:function(){}<br />}<br /><br />这等价于:<br />function c(){<br /> this.member1=value;<br /> this.member2=function(){};<br />}<br /><br />需要注意的是，用前一种办法时，最后一个成员的最后不能加逗号，我想这种语法应该和数组有关。<br />在js里，函数和类是没有区别的，都可以new，new的作用是把函数体的语句都执行一遍，然后返回一个对象。如果函数里有this，那么this后面的变量会作为对象成员；如果没有，那么new的作用只是返回一个没有任何成员的空对象。所以你用typeof查看一个所谓类的类型时，仍然会返回function。在js里也基本没有类型的概念，所有变量的声明都用var，即使是函数，也是如此。函数，其实也只是一个变量。<br />说函数是变量，可能很多人不解。但是你试试下面的做法：<br />function fTest(){<br /> var a=1;<br /> alert(a);<br />}<br />alert(fTest);<br /><br />你会发现显示的是fTest这个函数的函数体，所以我们可以认为，所谓函数，仅仅是js引擎可以解析的一段代码字符串。函数名变量存储的只是这个字符串。说的更准确一点，函数名是一个指针变量，它存储的是这个代码字符串在内存中的位置。这样就不难理解将函数作为参数传递，可以作为值返回了，这是以后会大量使用的技术。因为类也是函数，所以理解了函数，也就理解了类。<br />虽然在js里函数和类没有区别，但是类的概念却可以方便我们进行程序设计，于是prototype很有创意的创建了一个全局对象Class：<br />var Class = {<br />  create: function() {<br />    return function() { <br />      this.initialize.apply(this, arguments);<br />    }<br />  }<br />}<br /><br />Class是一个全局对象，它的唯一方法就是create，作用返回一个函数，前面已经讲过函数作为返回值的机制，这里不再遨述。返回的函数包括一条语句：<br />this.initialize.apply(this, arguments);<br /><br />前面讲过，new一个函数时，会执行函数里的代码，最后返回对象。所以当使用Class.create()创建了一个函数，再new这个返回的函数时，首先会执行这条语句。后面可以看到，这其实是为了调用类的构造函数。<br />就是这样，Class成为了整个prototype的类型创建模型，并且能很好的把类和函数在代码上区分开来。Class.create()仅仅是返回一个空类，而且它会默认为这个类是具有initialize方法的，所以要使用这个类，至少需要有一个构造函数，这就需要使用到类的继承。类只是一个函数，那么函数怎么继承呢？看起来匪夷所思，javascript能做到这一点，prototype使得实现更为优雅，至于它是怎么做到的，且听下回分解。<br />AJAX之旅(2)：javascript中类的深入研究－实现和继承 <br />上回说到了类的定义，prototype通过一个全局对象Class从形式上将函数和类区别开来。既然是类，那么就有抽象类，具体类，类的继承，同时，类的成员可以有实例成员和静态成员。下面来看一下prototype是怎么做到这些的。<br />先看prototype中的以下的代码： <br /><br />var Abstract = new Object(); <br /> Object.extend = function(destination, source) {<br />   for (property in source) {<br />     destination[property] = source[property];<br />   }<br />   return destination;<br /> } <br /> Object.prototype.extend = function(object) {<br />   return Object.extend.apply(this, [this, object]);<br /> }<br />第一个声明了一个对象Abstract，Object其实是一个函数，他没有任何成员，所以是一个空类，所以Abstract也就没有任何成员。这个暂时不说，后面可以看到这是抽象类的基础。先解释以下这个语法：<br />function.member=function(){}<br />在这种情况下，function一般都是已经定义过的，这条语句的作用是给function增加一个静态成员member，member的内容是等号后面的。如上面第二段代码Object.extend=……，就是给Object这个类增加了一个静态方法extend。ok，我们知道了怎样给一个类定义静态成员，那么你一定很想知道实例成员怎么定义，很简单，在类名和成员名之间加上prototype： <br /><br />function.prototype.member=function(){}<br /> <br />prototype不仅可以这么使用，还可以： <br /> function.prototype={<br />  member1:function(){……},<br />  member2:"abc",<br />  member3:function(){……}<br /> }<br />这样就是实现了实例成员的定义。但prototype代表什么意思呢？在第一篇我说过，直接用{}括起来，表示一个对象，如Prototype，Class都是这样定义的全局对象。而看下面一种用法，prototype后面就是一个{}的结构，难道它也是对象？是的，没错，prototype其实也是一个对象！在javascript里，一个对象我们可以任意增加它的成员，用如下的语法：<br />object.member=function(){……};<br />只要经过这样的定义，一个对象就可以立刻具有member这个方法！javascript就是这么神奇！<br />好，我们现在知道了prototype是一个对象，而function是一个函数或者类，那么我们可以认为prototype是任何一个类（函数）都内部保留的一个静态成员。它的功能就是存储这个类的所有成员指针，但这些成员都只是原型，没有经过初始化，这也符合prototype的原义。你可以随时通过prototype这个对象来扩充成员。在new一个类时，prototype的成员就经过初始化，然后赋给了实例化的对象。<br />上面第三段代码Object.prototype.extend=……，就是给Object增加了一个实例方法extend，实例方法中就可以引用this指针，指向由这个类实例化的对象本身。当然，这个对象就具有成员extend。<br />继续之前，先了解一下两个语句： <br />for(var p in object){}<br /> method.apply(object,arguments);<br />第一句：列举出一个变量的所有成员，如果是函数，那么是所有静态成员；如果是对象，那就是所有实例成员，p的类型是一个字符串。表示成员的名称。引用一个成员不仅可以用variabel.member，还可以用variabel["member"]。反过来，赋值也是如此。这就给枚举一个变量的成员带来了很大方便。<br />第二条语句：将method这个方法应用到object去执行，参数是arguments这个数组。注意：method并不是object的成员。但是，我们可以认为这条语句执行的意思就是：object.method(arguments)。这是一个很重要的方法，后面会经常用到，你也会逐渐熟悉它的。<br />下面继续extend，它是一个非常重要的方法，可以看到它既是类Object的静态成员，也是其实例成员，那它有什么作用呢？让我们来看：它接收两个参数，destination和source，如果destination和source都是类，那么它的功能是把类source的所有静态成员都复制给类destination，如果destination和source都是对象，那么是把所有实例成员都复制过来。这时destination中如果已经有同名成员，那么这个成员将被覆盖。也就是说让destination具有了source的所有成员，并且函数返回这个destination。下面看extend作为Object的实例成员：<br />Object.prototype.extend = function(object) {<br />   return Object.extend.apply(this, [this, object]);<br /> }<br />开始有点晕了，不过不要急，还是可以看懂的，apply语法刚刚已经讲过了，它的调用者是一个方法，而Object.extend是一个静态方法，它被应用到this上面，也就是Object的实例，假设为obj，后面方括号是一个数组，包括两个成员，this和object。这个数组实际上就是Object静态成员extend的arguments参数。那么这条语句就相当于执行 <br />obj.extend(this,object);<br />this不解释了，表示本身。object是什么？参数，恩，是实例方法extend传来的参数，不要混淆。extend呢？obj并没有定义extend实例成员，但通过apply，它可以把Object的静态成员extend拿来使用，再看一下extend的函数体： <br />Object.extend = function(destination, source) {<br />   for (property in source) {<br />     destination[property] = source[property];<br />   }<br />   return destination;<br /> }<br />因为obj是对象，object也是对象，即destination和source都是对象，于是函数的作用就是使obj具有object的所有成员。并且会返回obj。听起来有点拗口，但逻辑很简单：让obj“继承于”object！很好，我们看到了继承，但你肯定会问，对象的继承，第一次听说啊，我们讲继承都是讲的类的继承。没错，现在的确还没有看到真正的类继承，但已经近在眼前了：类不就是有个prototype吗，而prototype是对象！<br />好，想到这一点，类的继承语法看似很简单了： <br />b.prototype.extend(a.prototype);<br />让b继承a。<br />可是事实却没那么简单：prototype是存放方法原型指针，extend方法没有初始化，不能使用！要使用extend，就必须实例化一个对象。还是看看prototype是怎么做的吧：<br />b.prototype=(new a()).extend(b.prototype);<br />很高明的办法！充分说明了函数其实也是一个变量的道理。先实例化a对象，然后在它基础上调用extend，将所有的成员b.prototype的成员覆盖到a的对象，然后把这个a对象再赋值给b.prototype。完成了b从a继承的工作。在实际使用中，一般的用法都是：<br />b.prototype=(new a()).extend({});<br />因为让一个b继承自a，通常b之前都是一个未定义的类，所以后面的{}中其实就可以定义类成员。当然，你也可以先定义，再继承，只是和传统概念有所区别了。<br /><br />AJAX之旅（3）：javascript中的事件设计模式 <br />今天暂时抛开prototype1.3.1，分享一下我的javscript事件设计心得。其实现的技术基础在于函数的本质，这在前面两篇中有详细叙述（更多请关注：http://www.x2design.net）。<br />javascript内置的对象都有事件功能，比如button就有onclick事件，input就有onchange事件。那么如何在我们自定义的类中实现事件呢？很简单：<br />var myClass=Class.create();<br />myClass.prototype={<br /> show:function(){<br />  //statement<br />  onshow();<br /> },<br /> onshow:function(){}<br />}<br />这段代码其实就是实现了onshow事件，在myClass实例show的时候触发，你可以给onshow绑定一个函数，从而使用事件功能。在javascript中，内置的对象事件使用方法都是如此，其内部实现应该也是基于这样的模式。但是，这样的实现却有两个突出的问题：<br />1.只能绑定一个回调函数。如果要实现多绑定，必须自己写很多代码来封装要回调的函数到一个函数中。<br />2.不能传递参数。因为onshow只能赋给函数名，即函数体本身，并不能传递参数进去，为了传递参数，我曾写过一篇：《用外壳包装法给javascript触发器传递参数》，可见，同样需要写很多代码。<br />那么，这些问题怎么解决呢？javascript内置对象的事件使用我们就暂时不管，来考虑一下怎么在自己实现的类中避免如上两个问题。实现之前，先来考虑下面这个问题，或许有助于理解实现这个功能的意义：<br />我的页面需要用javascript进行一些初始化，但初始化必须在页面载入完成之后进行。通常我们会将代码放到html文件最下面。但此时，在页面载入完成之前，页面上的按钮点击需要调用必须经过初始化的方法，如果不作判断，那么就很容易出现脚本错误。因为还没有初始化，一个简单的想法是：用一个bool变量loaded来判断，初始为false，初始化完成后为true，那么按钮点击时遇到false就简单返回。这实现固然简单，但有可能造成用户发现点击无效，而不知其所以然。所以完善的做法应该是能捕获这个方法，将其绑定到页面载入完成事件上，当页面载入完成后自动调用。<br />好，现在看事件设计模式的实现代码：<br />var myClass=Class.create();<br />myClass.prototype={<br /> initialize:function(){<br />  this.initEvent=new Object();<br /> },<br /> init:function(){<br />  //初始化要执行的语句<br />  <br />  //下面是调用绑定的回调函数<br />  for(var p in this.initEvent){<br />   //extend是内置方法，不可作为回调关键字<br />   if(p=="extend")continue;<br />   this.initEvent[p].apply(_object,[]);<br />  }<br /> },<br /> attachOnInit:function(_key,_object,_method,_arguments){<br />  this.initEvent[_key]=createFunction(_object,_method,_arguments);<br /> },<br />}<br />function createFunction(_object,_method,_arguments){<br /> return function(){<br />  _method.apply(_object,_arguments);<br /> }<br />}<br />这段代码就实现了一个类myClass，具有init方法，触发oninit事件，使用时要想绑定一个事件，可以调用attachOnInit方法，参数的意思分别为：_key，回调参函数的唯一标识，如果重复，后者覆盖前者；_object回调函数的对象，如果是直接在script中的函数，可以传递this指针进去，即document对象；_method，要回调的函数，注意，这是一个函数名，不是字符串；_arguments，回调函数的参数数组。还有一个函数是createFunction，作用是包装一个函数，使其内置参数，这是外壳包装法那篇文章的一个通用实现。如果大家看过ajax之旅系列的前两篇文章，应该容易理解上面的代码，如果有什么问题，欢迎评论。<br />使用示例：<br />function myFunc(s){<br /> alert(s);<br />}<br />var myObj=new myClass();<br />myClass.attach("key1",this,myFunc,[123]);<br />myClass.init();<br /><br />这就将myFunc函数绑定到myObj的init函数，执行后会弹出对话框123。<br /> <br />Ajax::prototype 源码解读 之 prototype.js 一[转载] <br />/** <br /> * 定义一个全局对象, 属性 Version 在发布的时候会替换为当前版本号 <br /> */ <br />var Prototype = { <br />  Version: '@@VERSION@@' <br />} <br /><br />/** <br /> * 创建一种类型，注意其属性 create 是一个方法，返回一个构造函数。 <br /> * 一般使用如下  <br /> *     var X = Class.create();  返回一个类型，类似于 java 的一个Class实例。 <br /> * 要使用 X 类型，需继续用 new X()来获取一个实例，如同 java 的 Class.newInstance()方法。 <br /> * <br /> * 返回的构造函数会执行名为 initialize 的方法， initialize 是 Ruby 对象的构造器方法名字。 <br /> * 此时initialize方法还没有定义，其后的代码中创建新类型时会建立相应的同名方法。 <br /> * <br /> * 如果一定要从java上去理解。你可以理解为用Class.create()创建一个继承java.lang.Class类的类。当然java不允许这样做，因为Class类是final的 <br /> * <br /> */ <br />var Class = { <br />  create: function() { <br />    return function() { <br />      this.initialize.apply(this, arguments); <br />    } <br />  } <br />} <br /><br />/** <br /> * 创建一个对象，从变量名来思考，本意也许是定义一个抽象类，以后创建新对象都 extend 它。 <br /> * 但从其后代码的应用来看， Abstract 更多是为了保持命名空间清晰的考虑。 <br /> * 也就是说，我们可以给 Abstract 这个对象实例添加新的对象定义。 <br /> * <br /> * 从java去理解，就是动态给一个对象创建内部类。 <br /> */ <br />var Abstract = new Object(); <br /><br />/** <br /> * 获取参数对象的所有属性和方法，有点象多重继承。但是这种继承是动态获得的。 <br /> * 如： <br /> *     var a = new ObjectA(), b = new ObjectB(); <br /> *     var c = a.extend(b); <br /> * 此时 c 对象同时拥有 a 和 b 对象的属性和方法。但是与多重继承不同的是，c instanceof ObjectB 将返回false。 <br /> */ <br />Object.prototype.extend = function(object) { <br />  for (property in object) { <br />    this[property] = object[property]; <br />  } <br />  return this; <br />} <br /><br />/** <br /> * 这个方法很有趣，它封装一个javascript函数对象，返回一个新函数对象，新函数对象的主体和原对象相同，但是bind()方法参数将被用作当前对象的对象。 <br /> * 也就是说新函数中的 this 引用被改变为参数提供的对象。 <br /> * 比如： <br /> *     &lt;input type="text" id="aaa" value="aaa"> <br /> *     &lt;input type="text" id="bbb" value="bbb"> <br /> *     ................. <br /> *     &lt;script> <br /> *         var aaa = document.getElementById("aaa"); <br /> *         var bbb = document.getElementById("bbb"); <br /> *         aaa.showValue = function() {alert(this.value);} <br /> *         aaa.showValue2 = aaa.showValue.bind(bbb); <br /> *     &lt;/script> <br /> *  那么，调用aaa.showValue 将返回"aaa", 但调用aaa.showValue2 将返回"bbb"。 <br /> * <br /> * apply 是ie5.5后才出现的新方法(Netscape好像很早就支持了)。 <br /> * 该方法更多的资料参考MSDN http://msdn.microsoft.com/library/en-us/script56/html/js56jsmthApply.asp <br /> * 还有一个 call 方法，应用起来和 apply 类似。可以一起研究下。 <br /> */ <br />Function.prototype.bind = function(object) { <br />  var method = this; <br />  return function() { <br />    method.apply(object, arguments); <br />  } <br />} <br /><br />/** <br /> * 和bind一样，不过这个方法一般用做html控件对象的事件处理。所以要传递event对象 <br /> * 注意这时候，用到了 Function.call。它与 Function.apply 的不同好像仅仅是对参数形式的定义。 <br /> * 如同 java 两个过载的方法。 <br /> */ <br />Function.prototype.bindAsEventListener = function(object) { <br />  var method = this; <br />  return function(event) { <br />    method.call(object, event || window.event); <br />  } <br />} <br /><br />/** <br /> * 将整数形式RGB颜色值转换为HEX形式 <br /> */ <br />Number.prototype.toColorPart = function() { <br />  var digits = this.toString(16); <br />  if (this &lt; 16) return '0' + digits; <br />  return digits; <br />} <br /><br />/** <br /> * 典型 Ruby 风格的函数，将参数中的方法逐个调用，返回第一个成功执行的方法的返回值 <br /> */ <br />var Try = { <br />  these: function() { <br />    var returnValue; <br />    <br />    for (var i = 0; i &lt; arguments.length; i++) { <br />      var lambda = arguments[i]; <br />      try { <br />        returnValue = lambda(); <br />        break; <br />      } catch (e) {} <br />    } <br />    <br />    return returnValue; <br />  } <br />} <br /><br />/*--------------------------------------------------------------------------*/ <br /><br />/** <br /> * 一个设计精巧的定时执行器 <br /> * 首先由 Class.create() 创建一个 PeriodicalExecuter 类型， <br /> * 然后用对象直接量的语法形式设置原型。 <br /> * <br /> * 需要特别说明的是 rgisterCallback 方法，它调用上面定义的函数原型方法bind, 并传递自己为参数。 <br /> * 之所以这样做，是因为 setTimeout 默认总以 window 对象为当前对象，也就是说，如果 registerCallback 方法定义如下的话： <br /> *     registerCallback: function() { <br /> *         setTimeout(this.onTimerEvent, this.frequency * 1000); <br /> *     } <br /> * 那么，this.onTimeoutEvent 方法执行失败，因为它无法访问 this.currentlyExecuting 属性。 <br /> * 而使用了bind以后，该方法才能正确的找到this，也就是PeriodicalExecuter的当前实例。 <br /> */ <br />var PeriodicalExecuter = Class.create(); <br />PeriodicalExecuter.prototype = { <br />  initialize: function(callback, frequency) { <br />    this.callback = callback; <br />    this.frequency = frequency; <br />    this.currentlyExecuting = false; <br />    <br />    this.registerCallback(); <br />  }, <br />  <br />  registerCallback: function() { <br />    setTimeout(this.onTimerEvent.bind(this), this.frequency * 1000); <br />  }, <br />  <br />  onTimerEvent: function() { <br />    if (!this.currentlyExecuting) { <br />      try { <br />        this.currentlyExecuting = true; <br />        this.callback(); <br />      } finally { <br />        this.currentlyExecuting = false; <br />      } <br />    } <br />    <br />    this.registerCallback(); <br />  } <br />} <br /><br />/*--------------------------------------------------------------------------*/ <br /><br />/** <br /> * 这个函数就 Ruby 了。我觉得它的作用主要有两个 <br /> * 1.  大概是 document.getElementById(id) 的最简化调用。 <br /> * 比如：$("aaa") 将返回上 aaa 对象 <br /> * 2.  得到对象数组 <br /> * 比如: $("aaa","bbb") 返回一个包括id为"aaa"和"bbb"两个input控件对象的数组。 <br /> */ <br />function $() { <br />  var elements = new Array(); <br />  <br />  for (var i = 0; i &lt; arguments.length; i++) { <br />    var element = arguments[i]; <br />    if (typeof element == 'string') <br />      element = document.getElementById(element); <br /><br />    if (arguments.length == 1) <br />      return element; <br />      <br />    elements.push(element); <br />  } <br />  <br />  return elements; <br />}<br /><br /><br />Ajax::prototype 源码解读 之 prototype.js 二[转载] <br />/** <br /> * 定义 Ajax 对象, 静态方法 getTransport 方法返回一个 XMLHttp 对象 <br /> */ <br />var Ajax = { <br />  getTransport: function() { <br />    return Try.these( <br />      function() {return new ActiveXObject('Msxml2.XMLHTTP')}, <br />      function() {return new ActiveXObject('Microsoft.XMLHTTP')}, <br />      function() {return new XMLHttpRequest()} <br />    ) || false; <br />  }, <br />  <br />  emptyFunction: function() {} <br />} <br /><br />/** <br /> * 我以为此时的Ajax对象起到命名空间的作用。 <br /> * Ajax.Base 声明为一个基础对象类型 <br /> * 注意 Ajax.Base 并没有使用 Class.create() 的方式来创建，我想是因为作者并不希望 Ajax.Base 被库使用者实例化。 <br /> * 作者在其他对象类型的声明中，将会继承于它。 <br /> * 就好像 java 中的私有抽象类 <br /> */ <br />Ajax.Base = function() {}; <br />Ajax.Base.prototype = { <br />  /** <br />   * extend (见prototype.js中的定义) 的用法真是让人耳目一新 <br />   * options 首先设置默认属性，然后再 extend 参数对象，那么参数对象中也有同名的属性，那么就覆盖默认属性值。 <br />   * 想想如果我写这样的实现，应该类似如下： <br />     setOptions: function(options) { <br />      this.options.methed = options.methed? options.methed : 'post'; <br />      .......... <br />     } <br />     我想很多时候，java 限制了 js 的创意。 <br />   */ <br />  setOptions: function(options) { <br />    this.options = { <br />      method:       'post', <br />      asynchronous: true, <br />      parameters:   '' <br />    }.extend(options || {}); <br />  } <br />} <br /><br /><br />/** <br /> * Ajax.Request 封装 XmlHttp <br /> */ <br />Ajax.Request = Class.create(); <br /><br />/** <br /> * 定义四种事件(状态)， 参考http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/readystate_1.asp <br /> */ <br />Ajax.Request.Events = <br />  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; <br /><br />/** <br /> * <br /> */ <br />Ajax.Request.prototype = (new Ajax.Base()).extend({ <br />  initialize: function(url, options) { <br />    this.transport = Ajax.getTransport(); <br />    this.setOptions(options); <br />  <br />    try { <br />      if (this.options.method == 'get') <br />        url += '?' + this.options.parameters + '&_='; <br />    <br />     /** <br />      * 此处好像强制使用了异步方式，而不是依照 this.options.asynchronous 的值 <br />      */ <br />      this.transport.open(this.options.method, url, true); <br />      <br />     /** <br />      * 这里提供了 XmlHttp 传输过程中每个步骤的回调函数 <br />      */ <br />      if (this.options.asynchronous) { <br />        this.transport.onreadystatechange = this.onStateChange.bind(this); <br />        setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); <br />      } <br />              <br />      this.transport.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); <br />      this.transport.setRequestHeader('X-Prototype-Version', Prototype.Version); <br /><br />      if (this.options.method == 'post') { <br />        this.transport.setRequestHeader('Connection', 'close'); <br />        this.transport.setRequestHeader('Content-type', <br />          'application/x-www-form-urlencoded'); <br />      } <br />      <br />      this.transport.send(this.options.method == 'post' ? <br />        this.options.parameters + '&_=' : null); <br />                      <br />    } catch (e) { <br />    }    <br />  }, <br />      <br />  onStateChange: function() { <br />    var readyState = this.transport.readyState; <br />   /** <br />    * 如果不是 Loading 状态，就调用回调函数 <br />     */ <br />    if (readyState != 1) <br />      this.respondToReadyState(this.transport.readyState); <br />  }, <br />  <br />  /** <br />   * 回调函数定义在 this.options 属性中，比如: <br />      var option = { <br />         onLoaded : function(req) {...}; <br />         ...... <br />      } <br />      new Ajax.Request(url, option); <br />   */ <br />  respondToReadyState: function(readyState) { <br />    var event = Ajax.Request.Events[readyState]; <br />    (this.options['on' + event] || Ajax.emptyFunction)(this.transport); <br />  } <br />}); <br /><br />/** <br /> * Ajax.Updater 用于绑定一个html元素与 XmlHttp调用的返回值。类似与 buffalo 的 bind。 <br /> * 如果 options 中有 insertion(from dom.js) 对象的话, insertion 能提供更多的插入控制。 <br /> */ <br />Ajax.Updater = Class.create(); <br />Ajax.Updater.prototype = (new Ajax.Base()).extend({ <br />  initialize: function(container, url, options) { <br />    this.container = $(container); <br />    this.setOptions(options); <br />  <br />    if (this.options.asynchronous) { <br />      this.onComplete = this.options.onComplete; <br />      this.options.onComplete = this.updateContent.bind(this); <br />    } <br />    <br />    this.request = new Ajax.Request(url, this.options); <br />    <br />    if (!this.options.asynchronous) <br />      this.updateContent(); <br />  }, <br />  <br />  updateContent: function() { <br />    if (this.options.insertion) { <br />      new this.options.insertion(this.container, <br />        this.request.transport.responseText); <br />    } else { <br />      this.container.innerHTML = this.request.transport.responseText; <br />    } <br /><br />    if (this.onComplete) { <br />      setTimeout((function() {this.onComplete(this.request)}).bind(this), 10); <br />    } <br />  } <br />});<br />Ajax::prototype 源码解读 之 prototype.js 三[转载] <br />/** <br /> * 针对 页面元素对象 的工具类，提供一些简单静态方法 <br /> */ <br />var Field = { <br />  /** <br />   * 清除参数引用对象的值 <br />   */ <br />  clear: function() { <br />    for (var i = 0; i &lt; arguments.length; i++) <br />      $(arguments[i]).value = ''; <br />  }, <br /><br />  /** <br />   * 使参数引用对象获取焦点 <br />   */ <br />  focus: function(element) { <br />    $(element).focus(); <br />  }, <br />  <br />  /** <br />   * 判断参数引用对象值是否为空，如为空，返回false, 反之true <br />   */ <br />  present: function() { <br />    for (var i = 0; i &lt; arguments.length; i++) <br />      if ($(arguments[i]).value == '') return false; <br />    return true; <br />  }, <br />  <br />  /** <br />   * 使选中参数引用对象 <br />   */ <br />  select: function(element) { <br />    $(element).select(); <br />  }, <br /><br />  /** <br />   * 使参数引用对象处于可编辑状态 <br />   */ <br />  activate: function(element) { <br />    $(element).focus(); <br />    $(element).select(); <br />  } <br />} <br /><br />/*--------------------------------------------------------------------------*/ <br /><br />/** <br /> * 表单工具类 <br /> */ <br />var Form = { <br />  /** <br />   * 将表单元素序列化后的值组合成 QueryString 的形式 <br />   */ <br />  serialize: function(form) { <br />    var elements = Form.getElements($(form)); <br />    var queryComponents = new Array(); <br />    <br />    for (var i = 0; i &lt; elements.length; i++) { <br />      var queryComponent = Form.Element.serialize(elements[i]); <br />      if (queryComponent) <br />        queryComponents.push(queryComponent); <br />    } <br />    <br />    return queryComponents.join('&'); <br />  }, <br />  <br />  /** <br />   * 得到表单的所有元素对象 <br />   */ <br />  getElements: function(form) { <br />    form = $(form); <br />    var elements = new Array(); <br /><br />    for (tagName in Form.Element.Serializers) { <br />      var tagElements = form.getElementsByTagName(tagName); <br />      for (var j = 0; j &lt; tagElements.length; j++) <br />        elements.push(tagElements[j]); <br />    } <br />    return elements; <br />  }, <br />  <br />  /** <br />   * 将指定表单的元素置于不可用状态 <br />   */ <br />  disable: function(form) { <br />    var elements = Form.getElements(form); <br />    for (var i = 0; i &lt; elements.length; i++) { <br />      var element = elements[i]; <br />      element.blur(); <br />      element.disable = 'true'; <br />    } <br />  }, <br /><br />  /** <br />   * 使表单的第一个非 hidden 类型而且处于可用状态的元素获得焦点 <br />   */ <br />  focusFirstElement: function(form) { <br />    form = $(form); <br />    var elements = Form.getElements(form); <br />    for (var i = 0; i &lt; elements.length; i++) { <br />      var element = elements[i]; <br />      if (element.type != 'hidden' && !element.disabled) { <br />        Field.activate(element); <br />        break; <br />      } <br />    } <br />  }, <br /><br />  /* <br />   * 重置表单 <br />   */ <br />  reset: function(form) { <br />    $(form).reset(); <br />  } <br />} <br /><br />/** <br /> * 表单元素工具类 <br /> */ <br />Form.Element = { <br />  /** <br />   * 返回表单元素的值先序列化再进行 URL 编码后的值 <br />   */ <br />  serialize: function(element) { <br />    element = $(element); <br />    var method = element.tagName.toLowerCase(); <br />    var parameter = Form.Element.Serializers[method](element); <br />    <br />    if (parameter) <br />      return encodeURIComponent(parameter[0]) + '=' + <br />        encodeURIComponent(parameter[1]);                    <br />  }, <br />  <br />  /** <br />   *  返回表单元素序列化后的值 <br />   */ <br />  getValue: function(element) { <br />    element = $(element); <br />    var method = element.tagName.toLowerCase(); <br />    var parameter = Form.Element.Serializers[method](element); <br />    <br />    if (parameter) <br />      return parameter[1]; <br />  } <br />} <br /><br />/** <br /> * prototype 的所谓序列化其实就是将表单的名字和值组合成一个数组 <br /> */ <br />Form.Element.Serializers = { <br />  input: function(element) { <br />    switch (element.type.toLowerCase()) { <br />      case 'hidden': <br />      case 'password': <br />      case 'text': <br />        return Form.Element.Serializers.textarea(element); <br />      case 'checkbox':  <br />      case 'radio': <br />        return Form.Element.Serializers.inputSelector(element); <br />    } <br />    return false; <br />  }, <br />  <br />  inputSelector: function(element) { <br />    if (element.checked) <br />      return [element.name, element.value]; <br />  }, <br /><br />  textarea: function(element) { <br />    return [element.name, element.value]; <br />  }, <br /><br />  /** <br />   * 看样子，也不支持多选框(select-multiple) <br />   */ <br />  select: function(element) { <br />    var index = element.selectedIndex; <br />    var value = element.options[index].value || element.options[index].text; <br />    return [element.name, (index >= 0) ? value : '']; <br />  } <br />} <br /><br />/*--------------------------------------------------------------------------*/ <br /><br />/** <br /> * Form.Element.getValue 也许会经常用到，所以做了一个快捷引用 <br /> */ <br />var $F = Form.Element.getValue; <br /><br />/*--------------------------------------------------------------------------*/ <br /><br />/** <br /> * Abstract.TimedObserver 也没有用 Class.create() 来创建，和Ajax.Base 意图应该一样 <br /> * Abstract.TimedObserver 顾名思义，是套用Observer设计模式来跟踪指定表单元素， <br /> * 当表单元素的值发生变化的时候，就执行回调函数 <br /> * <br /> * 我想　Observer 与注册onchange事件相似，不同点在于 onchange 事件是在元素失去焦点的时候才激发。 <br /> * 同样的与 onpropertychange 事件也相似，不过它只关注表单元素的值的变化，而且提供timeout的控制。 <br /> * <br /> * 除此之外，Observer 的好处大概就在与更面向对象，另外可以动态的更换回调函数，这就比注册事件要灵活一些。 <br /> * Observer 应该可以胜任动态数据校验，或者多个关联下拉选项列表的连动等等 <br /> * <br /> */ <br />Abstract.TimedObserver = function() {} <br /><br />/** <br /> * 这个设计和 PeriodicalExecuter 一样，bind 方法是实现的核心 <br /> */ <br />Abstract.TimedObserver.prototype = { <br />  initialize: function(element, frequency, callback) { <br />    this.frequency = frequency; <br />    this.element   = $(element); <br />    this.callback  = callback; <br />    <br />    this.lastValue = this.getValue(); <br />    this.registerCallback(); <br />  }, <br />  <br />  registerCallback: function() { <br />    setTimeout(this.onTimerEvent.bind(this), this.frequency * 1000); <br />  }, <br />  <br />  onTimerEvent: function() { <br />    var value = this.getValue(); <br />    if (this.lastValue != value) { <br />      this.callback(this.element, value); <br />      this.lastValue = value; <br />    } <br />    <br />    this.registerCallback(); <br />  } <br />} <br /><br />/** <br /> * Form.Element.Observer 和 Form.Observer 其实是一样的 <br /> * 注意 Form.Observer 并不是用来跟踪整个表单的，我想大概只是为了减少书写(这是Ruby的一个设计原则) <br /> */ <br />Form.Element.Observer = Class.create(); <br />Form.Element.Observer.prototype = (new Abstract.TimedObserver()).extend({ <br />  getValue: function() { <br />    return Form.Element.getValue(this.element); <br />  } <br />}); <br /><br />Form.Observer = Class.create(); <br />Form.Observer.prototype = (new Abstract.TimedObserver()).extend({ <br />  getValue: function() { <br />    return Form.serialize(this.element); <br />  } <br />});<br />Ajax::prototype 源码解读 之 prototype.js 四[转载] <br />/** <br /> * 根据 class attribute 的名字得到对象数组，支持 multiple class <br /> * <br /> */ <br />document.getElementsByClassName = function(className) { <br />  var children = document.getElementsByTagName('*') || document.all; <br />  var elements = new Array(); <br />  <br />  for (var i = 0; i &lt; children.length; i++) { <br />    var child = children[i]; <br />    var classNames = child.className.split(' '); <br />    for (var j = 0; j &lt; classNames.length; j++) { <br />      if (classNames[j] == className) { <br />        elements.push(child); <br />        break; <br />      } <br />    } <br />  } <br />  <br />  return elements; <br />} <br /><br />/*--------------------------------------------------------------------------*/ <br /><br />/** <br /> * Element 就象一个 java 的工具类，主要用来 隐藏/显示/销除 对象，以及获取对象的简单属性。 <br /> * <br /> */ <br />var Element = { <br />  toggle: function() { <br />    for (var i = 0; i &lt; arguments.length; i++) { <br />      var element = $(arguments[i]); <br />      element.style.display = <br />        (element.style.display == 'none' ? '' : 'none'); <br />    } <br />  }, <br /><br />  hide: function() { <br />    for (var i = 0; i &lt; arguments.length; i++) { <br />      var element = $(arguments[i]); <br />      element.style.display = 'none'; <br />    } <br />  }, <br /><br />  show: function() { <br />    for (var i = 0; i &lt; arguments.length; i++) { <br />      var element = $(arguments[i]); <br />      element.style.display = ''; <br />    } <br />  }, <br /><br />  remove: function(element) { <br />    element = $(element); <br />    element.parentNode.removeChild(element); <br />  }, <br />    <br />  getHeight: function(element) { <br />    element = $(element); <br />    return element.offsetHeight; <br />  } <br />} <br /><br />/** <br /> * 为 Element.toggle 做了一个符号连接，大概是兼容性的考虑 <br /> */ <br />var Toggle = new Object(); <br />Toggle.display = Element.toggle; <br /><br />/*--------------------------------------------------------------------------*/ <br /><br />/** <br /> * 动态插入内容的实现，MS的Jscript实现中对象有一个 insertAdjacentHTML 方法(http: //msdn.microsoft.com/workshop/author/dhtml/reference/methods/insertadjacenthtml.asp) <br /> * 这里算是一个对象形式的封装。 <br /> */ <br />Abstract.Insertion = function(adjacency) { <br />  this.adjacency = adjacency; <br />} <br /><br />Abstract.Insertion.prototype = { <br />  initialize: function(element, content) { <br />    this.element = $(element); <br />    this.content = content; <br />    <br />    if (this.adjacency && this.element.insertAdjacentHTML) { <br />      this.element.insertAdjacentHTML(this.adjacency, this.content); <br />    } else { <br />     /** <br />      * gecko 不支持 insertAdjacentHTML 方法，但可以用如下代码代替 <br />      */ <br />      this.range = this.element.ownerDocument.createRange(); <br />     /** <br />      * 如果定义了 initializeRange 方法，则实行，这里相当与定义了一个抽象的 initializeRange 方法 <br />      */ <br />      if (this.initializeRange) this.initializeRange(); <br />      this.fragment = this.range.createContextualFragment(this.content); <br /><br />     /** <br />      * insertContent 也是一个抽象方法，子类必须实现 <br />      */ <br />      this.insertContent(); <br />    } <br />  } <br />} <br /><br />/** <br /> * prototype 加深了我的体会，就是写js 如何去遵循　Don’t Repeat Yourself (DRY) 原则 <br /> * 上文中 Abstract.Insertion 算是一个抽象类，定义了名为　initializeRange 的一个抽象方法 <br /> * var Insertion = new Object()　建立一个命名空间 <br /> * Insertion.Before|Top|Bottom|After 就象是四个java中的四个静态内部类，而它们分别继承于Abstract.Insertion，并实现了initializeRange方法。 <br /> */ <br />var Insertion = new Object(); <br /><br />Insertion.Before = Class.create(); <br />Insertion.Before.prototype = (new Abstract.Insertion('beforeBegin')).extend({ <br />  initializeRange: function() { <br />    this.range.setStartBefore(this.element); <br />  }, <br />  <br />  /** <br />   * 将内容插入到指定节点的前面, 与指定节点同级 <br />   */ <br />  insertContent: function() { <br />    this.element.parentNode.insertBefore(this.fragment, this.element); <br />  } <br />}); <br /><br />Insertion.Top = Class.create(); <br />Insertion.Top.prototype = (new Abstract.Insertion('afterBegin')).extend({ <br />  initializeRange: function() { <br />    this.range.selectNodeContents(this.element); <br />    this.range.collapse(true); <br />  }, <br />  <br />  /** <br />   * 将内容插入到指定节点的第一个子节点前，于是内容变为该节点的第一个子节点 <br />   */ <br />  insertContent: function() {  <br />    this.element.insertBefore(this.fragment, this.element.firstChild); <br />  } <br />}); <br /><br />Insertion.Bottom = Class.create(); <br />Insertion.Bottom.prototype = (new Abstract.Insertion('beforeEnd')).extend({ <br />  initializeRange: function() { <br />    this.range.selectNodeContents(this.element); <br />    this.range.collapse(this.element); <br />  }, <br />  <br />  /** <br />   * 将内容插入到指定节点的最后，于是内容变为该节点的最后一个子节点 <br />   */ <br />  insertContent: function() { <br />    this.element.appendChild(this.fragment); <br />  } <br />}); <br /><br /><br />Insertion.After = Class.create(); <br />Insertion.After.prototype = (new Abstract.Insertion('afterEnd')).extend({ <br />  initializeRange: function() { <br />    this.range.setStartAfter(this.element); <br />  }, <br /><br />  /** <br />   * 将内容插入到指定节点的后面, 与指定节点同级 <br />   */ <br />  insertContent: function() { <br />    this.element.parentNode.insertBefore(this.fragment, <br />      this.element.nextSibling); <br />  } <br />});<br /><br /> <br /><br />Ajax::prototype 源码解读 之 prototype.js 五[转载] <br />prototype 还有两个源码文件 effects.js compat.js 就不贴出来了。两者并不常用，effects.js 看example 做花哨的效果还不错，不过代码中没有太多新鲜的东西。 <br /><br />需要指出的就是 <br />compat.js 中 Funcation.prototype.apply 的实现有两个错误（应该是拼写错误）， 我分别贴出来，大家比较一下就清楚了。
          <br/>
          <span style="color:red;">
            <a href="http://jef.javaeye.com/blog/155985#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/115' target='_blank'><span style="color:red;font-weight:bold;">JavaEye图灵杯第2届问答大赛开始了！8月4日至8月17日，奖品丰厚！</span></a></li><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, 15 Jan 2008 12:45:30 +0800</pubDate>
        <link>http://jef.javaeye.com/blog/155985</link>
        <guid>http://jef.javaeye.com/blog/155985</guid>
      </item>
      <item>
        <title>一个分页支持类</title>
        <author>jef</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jef.javaeye.com">jef</a>&nbsp;
          链接：<a href="http://jef.javaeye.com/blog/150263" style="color:red;">http://jef.javaeye.com/blog/150263</a>&nbsp;
          发表时间: 2007年12月23日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          参考了http://www.javaeye.com/article/14657?page=3#comments文章中的PaginationSupport类实现(应用Hibernate3的DetachedCriteria实现分页查询 )。<br />对PaginationSupport做了部分补充，增加了reFresh(List items,int startIndex)方法用于刷新PaginationSupport类的状态。PaginationSupport对象放入Session中，PaginationSupport中记录queryString,分页索引,记录总量等，大数据量查询的时候第一次查询较慢，后续查询速度很快。<br /><br /><pre name="code" class="java">
import java.util.List;

/**
 * 	ps.getItems()得到已分页好的结果集 
 *		ps.getIndexes()得到分页索引的数组 
 *		ps.getTotalCount()得到总结果数 
 *		ps.getStartIndex()当前分页索引 
 *		ps.getNextIndex()下一页索引 
 *		ps.getPreviousIndex()上一页索引
 *     @see http://www.javaeye.com/article/14657?page=3#comments
 */
public class PaginationSupport {
  
    public final static int PAGESIZE = 30;   
  
    private int pageSize = PAGESIZE;
  
    private List items;
  
    private int totalCount;   
  
    private int[] indexes = new int[0];   
  
    private int startIndex = 0;
  
    public PaginationSupport(List items, int totalCount) {
        setPageSize(PAGESIZE);
        setTotalCount(totalCount);   
        setItems(items);
        setStartIndex(0);   
    }
  
    public PaginationSupport(List items, int totalCount, int startIndex) { 
        setPageSize(PAGESIZE);   
        setTotalCount(totalCount);   
        setItems(items);           
        setStartIndex(startIndex);   
    }
  
    public PaginationSupport(List items, int totalCount, int pageSize, int startIndex) {
        setPageSize(pageSize);   
        setTotalCount(totalCount);   
        setItems(items);   
        setStartIndex(startIndex);   
    } 
      
    public List getItems() {
        return items;   
    }
  
    public void setItems(List items) {   
        this.items = items;   
    }
  
    public int getPageSize() {
        return pageSize;   
    }   
  
    public void setPageSize(int pageSize) {   
        this.pageSize = pageSize;   
    }   
  
    public int getTotalCount() {   
        return totalCount;   
    }   
  
    public void setTotalCount(int totalCount) {   
        if (totalCount > 0) {   
            this.totalCount = totalCount;   
            // 81/10 = 8 
            int count = totalCount / pageSize;   
            if (totalCount % pageSize > 0)   
                count++;   
            indexes = new int[count];   
            for (int i = 0; i &lt; count; i++) {   
                indexes[i] = pageSize * i;   
            }   
        } else {   
            this.totalCount = 0;   
        }   
    }   
  
    public int[] getIndexes() {   
        return indexes;   
    }   
  
    public void setIndexes(int[] indexes) {   
        this.indexes = indexes;   
    }   
  
    public int getStartIndex() {   
        return startIndex;   
    }   
  
    public void setStartIndex(int startIndex) {   
        if (totalCount &lt;= 0)   
            this.startIndex = 0;   
        else if (startIndex >= totalCount)   
            this.startIndex = indexes[indexes.length - 1];   
        else if (startIndex &lt; 0)   
            this.startIndex = 0;   
        else {   
            this.startIndex = indexes[startIndex / pageSize];   
        }   
    }   
  
    public int getNextIndex() {
        int nextIndex = getStartIndex() + pageSize;   
        if (nextIndex >= totalCount)   
            return getStartIndex();   
        else  
            return nextIndex;
    }
  
    public int getPreviousIndex() {   
        int previousIndex = getStartIndex() - pageSize;   
        if (previousIndex &lt; 0)   
            return 0;   
        else  
            return previousIndex;   
    }
    
    
    //--------------------------------------------------------------------------------------------
    
    /**
     * 末页索引
     */
    public int getLastIndex(){
    	return getIndexes()[getIndexes().length-1];
    }
    
    /**
     * 刷新当前PaginationSupport对象的状态,将PaginationSupport对象放入Session中
     * 重复使用 避免获对totalCount的重复查询
     */
    public void reFresh(List items,int startIndex){
    	setItems(items);
        setStartIndex(startIndex);
    }
    
    /**
     * 分页总数
     */
    public int getTotalPageNum(){
    	return getIndexes().length;
    }
    
    /**
     * 获得当前页码
     */
    public int getCurrentPageNum(){
    	int[] indexs = getIndexes();
    	int startIndex = getStartIndex();
    	int i=0;
    	for(i=0;i&lt;indexs.length;i++){
    		if(startIndex == indexs[i])
    			break;
    	}
    	return (i+1);
    }
    
    public boolean hasPreviousPage(){
    	return getStartIndex()==0?false:true;
    }
    
    public boolean hasNextPage(){
    	return (getCurrentPageNum() == getTotalPageNum())?false:true;
    }
    
    private String queryString = null;

	public String getQueryString() {
		return queryString;
	}

	public void setQueryString(String queryString) {
		this.queryString = queryString;
	}
  
}  
</pre>
          <br/>
          <span style="color:red;">
            <a href="http://jef.javaeye.com/blog/150263#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/115' target='_blank'><span style="color:red;font-weight:bold;">JavaEye图灵杯第2届问答大赛开始了！8月4日至8月17日，奖品丰厚！</span></a></li><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>Sun, 23 Dec 2007 13:38:22 +0800</pubDate>
        <link>http://jef.javaeye.com/blog/150263</link>
        <guid>http://jef.javaeye.com/blog/150263</guid>
      </item>
  </channel>
</rss>