[转]prototype 源码解读 超强推荐第2/3页

 更新时间:2007年02月13日 00:00:00   作者:  
 
ajax.js 代码:
 
复制代码 代码如下:

/**  
2  
3  * 定义 Ajax 对象, 静态方法 getTransport 方法返回一个 XMLHttp 对象  
4  
5  */  
6   
7 var Ajax = {   
8   
9   getTransport: function() {   
10   
11     return Try.these(   
12   
13       function() {return new ActiveXObject('Msxml2.XMLHTTP')},   
14   
15       function() {return new ActiveXObject('Microsoft.XMLHTTP')},   
16   
17       function() {return new XMLHttpRequest()}   
18   
19     ) || false;   
20   
21   },   
22   
23   
24   emptyFunction: function() {}   
25   
26 }   
27   
28   
29 /**  
30  
31  * 我以为此时的Ajax对象起到命名空间的作用。  
32  
33  * Ajax.Base 声明为一个基础对象类型  
34  
35  * 注意 Ajax.Base 并没有使用 Class.create() 的方式来创建,我想是因为作者并不  
36  
37  * 希望 Ajax.Base 被库使用者实例化。  
38  
39  * 作者在其他对象类型的声明中,将会继承于它。  
40  
41  * 就好像 java 中的私有抽象类  
42  
43  */  
44   
45 Ajax.Base = function() {};   
46   
47 Ajax.Base.prototype = {   
48   
49   /**  
50  
51    * extend (见prototype.js中的定义) 的用法真是让人耳目一新  
52  
53    * options 首先设置默认属性,然后再 extend 参数对象,那么参数对象中也有同名  
54  
55    * 的属性,那么就覆盖默认属性值。  
56  
57    * 想想如果我写这样的实现,应该类似如下:  
58  
59      setOptions: function(options) {  
60  
61       this.options.methed = options.methed? options.methed : 'post';  
62  
63       ..........  
64  
65      }  
66  
67      我想很多时候,java 限制了 js 的创意。  
68  
69    */  
70   
71   setOptions: function(options) {   
72   
73     this.options = {   
74   
75       method:       'post',   
76   
77       asynchronous: true,   
78   
79       parameters:   ''  
80   
81     }.extend(options || {});   
82   
83   }   
84   
85 }   
86   
87   
88   
89 /**  
90  
91  * Ajax.Request 封装 XmlHttp  
92  
93  */  
94   
95 Ajax.Request = Class.create();   
96   
97   
98 /**  
99  
100  * 定义四种事件(状态), 参考  
101  
102  * http://msdn.microsoft.com/workshop/  
103  
104  * author/dhtml/reference/properties/readystate_1.asp  
105  
106  */  
107   
108 Ajax.Request.Events =   
109   
110   ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];   
111   
112   
113 /**  
114  
115  *  
116  
117  */  
118   
119 Ajax.Request.prototype = (new Ajax.Base()).extend({   
120   
121   initialize: function(url, options) {   
122   
123     this.transport = Ajax.getTransport();   
124   
125     this.setOptions(options);   
126   
127   
128     try {   
129   
130       if (this.options.method == 'get')   
131   
132         url += '?' + this.options.parameters + '&_=';   
133   
134   
135      /**  
136  
137       * 此处好像强制使用了异步方式,而不是依照 this.options.asynchronous 的值  
138  
139       */  
140   
141       this.transport.open(this.options.method, url, true);   
142   
143   
144      /**  
145  
146       * 这里提供了 XmlHttp 传输过程中每个步骤的回调函数  
147  
148       */  
149   
150       if (this.options.asynchronous) {   
151   
152         this.transport.onreadystatechange = this.onStateChange.bind(this);   
153   
154         setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);   
155   
156       }   
157   
158   
159       this.transport.setRequestHeader('X-Requested-With', 'XMLHttpRequest');   
160   
161       this.transport.setRequestHeader('X-Prototype-Version', Prototype.Version);   
162   
163   
164       if (this.options.method == 'post') {   
165   
166         this.transport.setRequestHeader('Connection', 'close');   
167   
168         this.transport.setRequestHeader('Content-type',   
169   
170           'application/x-www-form-urlencoded');   
171   
172       }   
173   
174   
175       this.transport.send(this.options.method == 'post' ?   
176   
177         this.options.parameters + '&_=' : null);   
178   
179   
180     } catch (e) {   
181   
182     }   
183   
184   },   
185   
186   
187   onStateChange: function() {   
188   
189     var readyState = this.transport.readyState;   
190   
191    /**  
192  
193     * 如果不是 Loading 状态,就调用回调函数  
194  
195      */  
196   
197     if (readyState != 1)   
198   
199       this.respondToReadyState(this.transport.readyState);   
200   
201   },   
202   
203   
204   /**  
205  
206    * 回调函数定义在 this.options 属性中,比如:  
207  
208       var option = {  
209  
210          onLoaded : function(req) {...};  
211  
212          ......  
213  
214       }  
215  
216       new Ajax.Request(url, option);  
217  
218    */  
219   
220   respondToReadyState: function(readyState) {   
221   
222     var event = Ajax.Request.Events[readyState];   
223   
224     (this.options['on' + event] || Ajax.emptyFunction)(this.transport);   
225   
226   }   
227   
228 });   
229   
230   
231 /**  
232  
233  * Ajax.Updater 用于绑定一个html元素与 XmlHttp调用的返回值。  
234  
235  * 类似与 buffalo 的 bind。  
236  
237  * 如果 options 中有 insertion(from dom.js) 对象的话,  
238  
239  * insertion 能提供更多的插入控制。  
240  
241  */  
242   
243 Ajax.Updater = Class.create();   
244   
245 Ajax.Updater.prototype = (new Ajax.Base()).extend({   
246   
247   initialize: function(container, url, options) {   
248   
249     this.container = $(container);   
250   
251     this.setOptions(options);   
252   
253   
254     if (this.options.asynchronous) {   
255   
256       this.onComplete = this.options.onComplete;   
257   
258       this.options.onComplete = this.updateContent.bind(this);   
259   
260     }   
261   
262   
263     this.request = new Ajax.Request(url, this.options);   
264   
265   
266     if (!this.options.asynchronous)   
267   
268       this.updateContent();   
269   
270   },   
271   
272   
273   updateContent: function() {   
274   
275     if (this.options.insertion) {   
276   
277       new this.options.insertion(this.container,   
278   
279         this.request.transport.responseText);   
280   
281     } else {   
282   
283       this.container.innerHTML = this.request.transport.responseText;   
284   
285     }   
286   
287   
288     if (this.onComplete) {   
289   
290       setTimeout((function() {this.onComplete(this.request)}).bind(this), 10);   
291   
292     }   
293   
294   }   
295   
296 });  

form.js 代码:
复制代码 代码如下:

/**  
2  
3  * 针对 页面元素对象 的工具类,提供一些简单静态方法  
4  
5  */  
6   
7 var Field = {   
8   
9   /**  
10  
11    * 清除参数引用对象的值  
12  
13    */  
14   
15   clear: function() {   
16   
17     for (var i = 0; i < arguments.length; i++)   
18   
19       $(arguments[i]).value = '';   
20   
21   },   
22   
23   
24   /**  
25  
26    * 使参数引用对象获取焦点  
27  
28    */  
29   
30   focus: function(element) {   
31   
32     $(element).focus();   
33   
34   },   
35   
36   
37   /**  
38  
39    * 判断参数引用对象值是否为空,如为空,返回false, 反之true  
40  
41    */  
42   
43   present: function() {   
44   
45     for (var i = 0; i < arguments.length; i++)   
46   
47       if ($(arguments[i]).value == '') return false;   
48   
49     return true;   
50   
51   },   
52   
53   
54   /**  
55  
56    * 使选中参数引用对象  
57  
58    */  
59   
60   select: function(element) {   
61   
62     $(element).select();   
63   
64   },   
65   
66   
67   /**  
68  
69    * 使参数引用对象处于可编辑状态  
70  
71    */  
72   
73   activate: function(element) {   
74   
75     $(element).focus();   
76   
77     $(element).select();   
78   
79   }   
80   
81 }   
82   
83   
84 /*-----------------------------------------------------------------*/  
85   
86   
87 /**  
88  
89  * 表单工具类  
90  
91  */  
92   
93 var Form = {   
94   
95   /**  
96  
97    * 将表单元素序列化后的值组合成 QueryString 的形式  
98  
99    */  
100   
101   serialize: function(form) {   
102   
103     var elements = Form.getElements($(form));   
104   
105     var queryComponents = new Array();   
106   
107   
108     for (var i = 0; i < elements.length; i++) {   
109   
110       var queryComponent = Form.Element.serialize(elements[i]);   
111   
112       if (queryComponent)   
113   
114         queryComponents.push(queryComponent);   
115   
116     }   
117   
118   
119     return queryComponents.join('&');   
120   
121   },   
122   
123   
124   /**  
125  
126    * 得到表单的所有元素对象  
127  
128    */  
129   
130   getElements: function(form) {   
131   
132     form = $(form);   
133   
134     var elements = new Array();   
135   
136   
137     for (tagName in Form.Element.Serializers) {   
138   
139       var tagElements = form.getElementsByTagName(tagName);   
140   
141       for (var j = 0; j < tagElements.length; j++)   
142   
143         elements.push(tagElements[j]);   
144   
145     }   
146   
147     return elements;   
148   
149   },   
150   
151   
152   /**  
153  
154    * 将指定表单的元素置于不可用状态  
155  
156    */  
157   
158   disable: function(form) {   
159   
160     var elements = Form.getElements(form);   
161   
162     for (var i = 0; i < elements.length; i++) {   
163   
164       var element = elements[i];   
165   
166       element.blur();   
167   
168       element.disable = 'true';   
169   
170     }   
171   
172   },   
173   
174   
175   /**  
176  
177    * 使表单的第一个非 hidden 类型而且处于可用状态的元素获得焦点  
178  
179    */  
180   
181   focusFirstElement: function(form) {   
182   
183     form = $(form);   
184   
185     var elements = Form.getElements(form);   
186   
187     for (var i = 0; i < elements.length; i++) {   
188   
189       var element = elements[i];   
190   
191       if (element.type != 'hidden' && !element.disabled) {   
192   
193         Field.activate(element);   
194   
195         break;   
196   
197       }   
198   
199     }   
200   
201   },   
202   
203   
204   /*  
205  
206    * 重置表单  
207  
208    */  
209   
210   reset: function(form) {   
211   
212     $(form).reset();   
213   
214   }   
215   
216 }   
217   
218   
219 /**  
220  
221  * 表单元素工具类  
222  
223  */  
224   
225 Form.Element = {   
226   
227   /**  
228  
229    * 返回表单元素的值先序列化再进行 URL 编码后的值  
230  
231    */  
232   
233   serialize: function(element) {   
234   
235     element = $(element);   
236   
237     var method = element.tagName.toLowerCase();   
238   
239     var parameter = Form.Element.Serializers[method](element);   
240   
241   
242     if (parameter)   
243   
244       return encodeURIComponent(parameter[0]) + '=' +   
245   
246         encodeURIComponent(parameter[1]);   
247   
248   },   
249   
250   
251   /**  
252  
253    *  返回表单元素序列化后的值  
254  
255    */  
256   
257   getValue: function(element) {   
258   
259     element = $(element);   
260   
261     var method = element.tagName.toLowerCase();   
262   
263     var parameter = Form.Element.Serializers[method](element);   
264   
265   
266     if (parameter)   
267   
268       return parameter[1];   
269   
270   }   
271   
272 }   
273   
274   
275 /**  
276  
277  * prototype 的所谓序列化其实就是将表单的名字和值组合成一个数组  
278  
279  */  
280   
281 Form.Element.Serializers = {   
282   
283   input: function(element) {   
284   
285     switch (element.type.toLowerCase()) {   
286   
287       case 'hidden':   
288   
289       case 'password':   
290   
291       case 'text':   
292   
293         return Form.Element.Serializers.textarea(element);   
294   
295       case 'checkbox':   
296   
297       case 'radio':   
298   
299         return Form.Element.Serializers.inputSelector(element);   
300   
301     }   
302   
303     return false;   
304   
305   },   
306   
307   
308   inputSelector: function(element) {   
309   
310     if (element.checked)   
311   
312       return [element.name, element.value];   
313   
314   },   
315   
316   
317   textarea: function(element) {   
318   
319     return [element.name, element.value];   
320   
321   },   
322   
323   
324   /**  
325  
326    * 看样子,也不支持多选框(select-multiple)  
327  
328    */  
329   
330   select: function(element) {   
331   
332     var index = element.selectedIndex;   
333   
334     var value = element.options[index].value || element.options[index].text;   
335   
336     return [element.name, (index >= 0) ? value : ''];   
337   
338   }   
339   
340 }   
341   
342   
343 /*--------------------------------------------------------------------------*/  
344   
345   
346 /**  
347  
348  * Form.Element.getValue 也许会经常用到,所以做了一个快捷引用  
349  
350  */  
351   
352 var $F = Form.Element.getValue;   
353   
354   
355 /*--------------------------------------------------------------------------*/  
356   
357   
358 /**  
359  
360  * Abstract.TimedObserver 也没有用 Class.create() 来创建,  
361  
362  * 和Ajax.Base 意图应该一样  
363  
364  * Abstract.TimedObserver 顾名思义,  
365  
366  * 是套用Observer设计模式来跟踪指定表单元素,  
367  
368  * 当表单元素的值发生变化的时候,就执行回调函数  
369  
370  *  
371  
372  * 我想 Observer 与注册onchange事件相似,  
373  
374  * 不同点在于 onchange 事件是在元素失去焦点  
375  
376  * 的时候才激发。  
377  
378  * 同样的与 onpropertychange 事件也相似,  
379  
380  * 不过它只关注表单元素的值的变化,而且提供timeout的控制。  
381  
382  *  
383  
384  * 除此之外,Observer 的好处大概就在与更面向对象,另外可以动态的更换回调函数,  
385  
386  * 这就比注册事件要灵活一些。  
387  
388  * Observer 应该可以胜任动态数据校验,或者多个关联下拉选项列表的连动等等  
389  
390  *  
391  
392  */  
393   
394 Abstract.TimedObserver = function() {}   
395   
396   
397 /**  
398  
399  * 这个设计和 PeriodicalExecuter 一样,bind 方法是实现的核心  
400  
401  */  
402   
403 Abstract.TimedObserver.prototype = {   
404   
405   initialize: function(element, frequency, callback) {   
406   
407     this.frequency = frequency;   
408   
409     this.element   = $(element);   
410   
411     this.callback  = callback;   
412   
413   
414     this.lastValue = this.getValue();   
415   
416     this.registerCallback();   
417   
418   },   
419   
420   
421   registerCallback: function() {   
422   
423     setTimeout(this.onTimerEvent.bind(this), this.frequency * 1000);   
424   
425   },   
426   
427   
428   onTimerEvent: function() {   
429   
430     var value = this.getValue();   
431   
432     if (this.lastValue != value) {   
433   
434       this.callback(this.element, value);   
435   
436       this.lastValue = value;   
437   
438     }   
439   
440   
441     this.registerCallback();   
442   
443   }   
444   
445 }   
446   
447   
448 /**  
449  
450  * Form.Element.Observer 和 Form.Observer 其实是一样的  
451  
452  * 注意 Form.Observer 并不是用来跟踪整个表单的,我想大概只是  
453  
454  * 为了减少书写(这是Ruby的一个设计原则)  
455  
456  */  
457   
458 Form.Element.Observer = Class.create();   
459   
460 Form.Element.Observer.prototype = (new Abstract.TimedObserver()).extend({   
461   
462   getValue: function() {   
463   
464     return Form.Element.getValue(this.element);   
465   
466   }   
467   
468 });   
469   
470   
471 Form.Observer = Class.create();   
472   
473 Form.Observer.prototype = (new Abstract.TimedObserver()).extend({   
474   
475   getValue: function() {   
476   
477     return Form.serialize(this.element);   
478   
479   }   
480   
481 });  


相关文章

最新评论