[轉(zhuǎn)]prototype 源碼解讀 超強推薦第2/3頁
更新時間:2007年02月13日 00:00:00 作者:
ajax.js 代碼:
復(fù)制代碼 代碼如下:
/**
2
3 * 定義 Ajax 對象, 靜態(tài)方法 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 聲明為一個基礎(chǔ)對象類型
34
35 * 注意 Ajax.Base 并沒有使用 Class.create() 的方式來創(chuàng)建,我想是因為作者并不
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 首先設(shè)置默認(rèn)屬性,然后再 extend 參數(shù)對象,那么參數(shù)對象中也有同名
54
55 * 的屬性,那么就覆蓋默認(rèn)屬性值。
56
57 * 想想如果我寫這樣的實現(xiàn),應(yīng)該類似如下:
58
59 setOptions: function(options) {
60
61 this.options.methed = options.methed? options.methed : 'post';
62
63 ..........
64
65 }
66
67 我想很多時候,java 限制了 js 的創(chuàng)意。
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 * 定義四種事件(狀態(tài)), 參考
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 傳輸過程中每個步驟的回調(diào)函數(shù)
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 狀態(tài),就調(diào)用回調(diào)函數(shù)
194
195 */
196
197 if (readyState != 1)
198
199 this.respondToReadyState(this.transport.readyState);
200
201 },
202
203
204 /**
205
206 * 回調(diào)函數(shù)定義在 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調(diào)用的返回值。
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 代碼:
復(fù)制代碼 代碼如下:
/**
2
3 * 針對 頁面元素對象 的工具類,提供一些簡單靜態(tài)方法
4
5 */
6
7 var Field = {
8
9 /**
10
11 * 清除參數(shù)引用對象的值
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 * 使參數(shù)引用對象獲取焦點
27
28 */
29
30 focus: function(element) {
31
32 $(element).focus();
33
34 },
35
36
37 /**
38
39 * 判斷參數(shù)引用對象值是否為空,如為空,返回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 * 使選中參數(shù)引用對象
57
58 */
59
60 select: function(element) {
61
62 $(element).select();
63
64 },
65
66
67 /**
68
69 * 使參數(shù)引用對象處于可編輯狀態(tài)
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 * 將指定表單的元素置于不可用狀態(tài)
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 類型而且處于可用狀態(tài)的元素獲得焦點
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 * 返回表單元素的值先序列化再進(jìn)行 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 的所謂序列化其實就是將表單的名字和值組合成一個數(shù)組
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 也許會經(jīng)常用到,所以做了一個快捷引用
349
350 */
351
352 var $F = Form.Element.getValue;
353
354
355 /*--------------------------------------------------------------------------*/
356
357
358 /**
359
360 * Abstract.TimedObserver 也沒有用 Class.create() 來創(chuàng)建,
361
362 * 和Ajax.Base 意圖應(yīng)該一樣
363
364 * Abstract.TimedObserver 顧名思義,
365
366 * 是套用Observer設(shè)計模式來跟蹤指定表單元素,
367
368 * 當(dāng)表單元素的值發(fā)生變化的時候,就執(zhí)行回調(diào)函數(shù)
369
370 *
371
372 * 我想 Observer 與注冊onchange事件相似,
373
374 * 不同點在于 onchange 事件是在元素失去焦點
375
376 * 的時候才激發(fā)。
377
378 * 同樣的與 onpropertychange 事件也相似,
379
380 * 不過它只關(guān)注表單元素的值的變化,而且提供timeout的控制。
381
382 *
383
384 * 除此之外,Observer 的好處大概就在與更面向?qū)ο螅硗饪梢詣討B(tài)的更換回調(diào)函數(shù),
385
386 * 這就比注冊事件要靈活一些。
387
388 * Observer 應(yīng)該可以勝任動態(tài)數(shù)據(jù)校驗,或者多個關(guān)聯(lián)下拉選項列表的連動等等
389
390 *
391
392 */
393
394 Abstract.TimedObserver = function() {}
395
396
397 /**
398
399 * 這個設(shè)計和 PeriodicalExecuter 一樣,bind 方法是實現(xiàn)的核心
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的一個設(shè)計原則)
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 });
相關(guān)文章
滾動經(jīng)典最新話題[prototype框架]下編寫
滾動經(jīng)典最新話題[prototype框架]下編寫...2006-10-10初學(xué)prototype,發(fā)個JS接受URL參數(shù)的代碼
初學(xué)prototype,發(fā)個JS接受URL參數(shù)的代碼...2007-01-01Prototype源碼淺析 String部分(三)之HTML字符串處理
現(xiàn)在,String部分轉(zhuǎn)入具體的關(guān)聯(lián)應(yīng)用,分別對應(yīng)HTML字符串,JSON字符串和HTML中的腳本字符串2012-01-01Prototype Number對象 學(xué)習(xí)
這個對象提供一些操作數(shù)值類型的工具函數(shù)2009-07-07prototype Element學(xué)習(xí)筆記(篇二)
這一篇主要是要總論Element的所有函數(shù)。2008-10-10prototype Element學(xué)習(xí)筆記(篇一)
Element,哈哈哈。遇到正主了,到現(xiàn)在為止才遇到讓我高興的玩意。當(dāng)初Ext.Element可是花三千余行代碼專門來封裝啊。我倒要看一看它的代碼了。事實上prototype中我最想研究的只有兩個內(nèi)容:Element、Selector。這兩個東西是精華。2008-10-10Prototype 學(xué)習(xí) Prototype對象
Prototype 學(xué)習(xí) Prototype對象2009-07-07