Chinaunix首页 | 论坛 | 博客
  • 博客访问: 266546
  • 博文数量: 155
  • 博客积分: 2865
  • 博客等级: 少校
  • 技术积分: 1580
  • 用 户 组: 普通用户
  • 注册时间: 2006-03-03 12:34
文章分类

全部博文(155)

文章存档

2010年(2)

2008年(2)

2007年(32)

2006年(119)

我的朋友

分类:

2006-06-29 13:41:15

form.js 代码:

1 /**
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 });  
view plain | print | copy to clipboard | ?

dom.js 代码:

1 /**
2
3  * 根据 class attribute 的名字得到对象数组,支持 multiple class
4
5  *
6
7  */ 
8  
9 document.getElementsByClassName = function(className) {  
10  
11   var children = document.getElementsByTagName('*') || document.all;  
12  
13   var elements = new Array();  
14  
15  
16   for (var i = 0; i < children.length; i++) {  
17  
18     var child = children[i];  
19  
20     var classNames = child.className.split(' ');  
21  
22     for (var j = 0; j < classNames.length; j++) {  
23  
24       if (classNames[j] == className) {  
25  
26         elements.push(child);  
27  
28         break;  
29  
30       }  
31  
32     }  
33  
34   }  
35  
36  
37   return elements;  
38  
39 }  
40  
41  
42 /*--------------------------------------------------------------------------*/ 
43  
44  
45 /**
46
47  * Element 就象一个 java 的工具类,主要用来 隐藏/显示/销除 对象,
48
49  * 以及获取对象的简单属性。
50
51  *
52
53  */ 
54  
55 var Element = {  
56  
57   toggle: function() {  
58  
59     for (var i = 0; i < arguments.length; i++) {  
60  
61       var element = $(arguments[i]);  
62  
63       element.style.display =  
64  
65         (element.style.display == 'none' ? '' : 'none');  
66  
67     }  
68  
69   },  
70  
71  
72   hide: function() {  
73  
74     for (var i = 0; i < arguments.length; i++) {  
75  
76       var element = $(arguments[i]);  
77  
78       element.style.display = 'none';  
79  
80     }  
81  
82   },  
83  
84  
85   show: function() {  
86  
87     for (var i = 0; i < arguments.length; i++) {  
88  
89       var element = $(arguments[i]);  
90  
91       element.style.display = '';  
92  
93     }  
94  
95   },  
96  
97  
98   remove: function(element) {  
99  
100     element = $(element);  
101  
102     element.parentNode.removeChild(element);  
103  
104   },  
105  
106  
107   getHeight: function(element) {  
108  
109     element = $(element);  
110  
111     return element.offsetHeight;  
112  
113   }  
114  
115 }  
116  
117  
118 /**
119
120  * 为 Element.toggle 做了一个符号连接,大概是兼容性的考虑
121
122  */ 
123  
124 var Toggle = new Object();  
125  
126 Toggle.display = Element.toggle;  
127  
128  
129 /*--------------------------------------------------------------------------*/ 
130  
131  
132 /**
133
134  * 动态插入内容的实现,MS的Jscript实现中对象有一个 insertAdjacentHTML 方法
135
136  * 
137
138  * author/dhtml/reference/methods/insertadjacenthtml.asp
139
140  * 这里算是一个对象形式的封装。
141
142  */ 
143  
144 Abstract.Insertion = function(adjacency) {  
145  
146   this.adjacency = adjacency;  
147  
148 }  
149  
150  
151 Abstract.Insertion.prototype = {  
152  
153   initialize: function(element, content) {  
154  
155     this.element = $(element);  
156  
157     this.content = content;  
158  
159  
160     if (this.adjacency && this.element.insertAdjacentHTML) {  
161  
162       this.element.insertAdjacentHTML(this.adjacency, this.content);  
163  
164     } else {  
165  
166      /**
167
168       * gecko 不支持 insertAdjacentHTML 方法,但可以用如下代码代替
169
170       */ 
171  
172       this.range = this.element.ownerDocument.createRange();  
173  
174      /**
175
176       * 如果定义了 initializeRange 方法,则实行,
177
178       * 这里相当与定义了一个抽象的 initializeRange 方法
179
180       */ 
181  
182       if (this.initializeRange) this.initializeRange();  
183  
184       this.fragment = this.range.createContextualFragment(this.content);  
185  
186  
187      /**
188
189       * insertContent 也是一个抽象方法,子类必须实现
190
191       */ 
192  
193       this.insertContent();  
194  
195     }  
196  
197   }  
198  
199 }  
200  
201  
202 /**
203
204  * prototype 加深了我的体会,就是写js 如何去遵循 
205
206  * Don’t Repeat Yourself (DRY) 原则
207
208  * 上文中 Abstract.Insertion 算是一个抽象类,
209
210  * 定义了名为 initializeRange 的一个抽象方法
211
212  * var Insertion = new Object() 建立一个命名空间
213
214  * Insertion.Before|Top|Bottom|After 就象是四个java中
215
216  * 的四个静态内部类,而它们分别继承于
217
218  * Abstract.Insertion,并实现了initializeRange方法。
219
220  */ 
221  
222 var Insertion = new Object();  
223  
224  
225 Insertion.Before = Class.create();  
226  
227 Insertion.Before.prototype =  
228  
229   (new Abstract.Insertion('beforeBegin')).extend({  
230  
231   initializeRange: function() {  
232  
233     this.range.setStartBefore(this.element);  
234  
235   },  
236  
237  
238   /**
239
240    * 将内容插入到指定节点的前面, 与指定节点同级
241
242    */ 
243  
244   insertContent: function() {  
245  
246     this.element.parentNode.insertBefore(this.fragment, this.element);  
247  
248   }  
249  
250 });  
251  
252  
253 Insertion.Top = Class.create();  
254  
255 Insertion.Top.prototype =  
256  
257   (new Abstract.Insertion('afterBegin')).extend({  
258  
259   initializeRange: function() {  
260  
261     this.range.selectNodeContents(this.element);  
262  
263     this.range.collapse(true);  
264  
265   },  
266  
267  
268   /**
269
270    * 将内容插入到指定节点的第一个子节点前,于是内容变为该节点的第一个子节点
271
272    */ 
273  
274   insertContent: function() {  
275  
276     this.element.insertBefore(this.fragment, this.element.firstChild);  
277  
278   }  
279  
280 });  
281  
282  
283 Insertion.Bottom = Class.create();  
284  
285 Insertion.Bottom.prototype = (new Abstract.Insertion('beforeEnd')).extend({  
286  
287   initializeRange: function() {  
288  
289     this.range.selectNodeContents(this.element);  
290  
291     this.range.collapse(this.element);  
292  
293   },  
294  
295  
296   /**
297
298    * 将内容插入到指定节点的最后,于是内容变为该节点的最后一个子节点
299
300    */ 
301  
302   insertContent: function() {  
303  
304     this.element.appendChild(this.fragment);  
305  
306   }  
307  
308 });  
309  
310  
311  
312 Insertion.After = Class.create();  
313  
314 Insertion.After.prototype = (new Abstract.Insertion('afterEnd')).extend({  
315  
316   initializeRange: function() {  
317  
318     this.range.setStartAfter(this.element);  
319  
320   },  
321  
322  
323   /**
324
325    * 将内容插入到指定节点的后面, 与指定节点同级
326
327    */ 
328  
329   insertContent: function() {  
330  
331     this.element.parentNode.insertBefore(this.fragment,  
332  
333       this.element.nextSibling);  
334  
335   }  
336  
337 });  
view plain | print | copy to clipboard | ?

其他代码:

prototype 还有两个源码文件 effects.js compat.js 就不贴出来了。两者并不常用,effects.js 看example 做花哨的效果还不错,不过代码中没有太多新鲜的东西。

需要指出的就是
compat.js 中 Funcation.prototype.apply 的实现有两个错误(应该是拼写错误), 我分别贴出来,大家比较一下就清楚了。

1 /* 这是包含错误的原版本
2
3 if (!Function.prototype.apply) {
4
5 // Based on code from 
6
7 Function.prototype.apply = function(object, parameters) {
8
9 var parameterStrings = new Array();
10
11 if (!object) object = window;
12
13 if (!parameters) parameters = new Array();
14
15
16 for (var i = 0; i < parameters.length; i++)
17
18 parameterStrings[i] = 'x[' + i + ']'; //Error 1
19
20
21 object.__apply__ = this;
22
23 var result = eval('obj.__apply__(' + //Error 2
24
25 parameterStrings[i].join(', ') + ')');
26
27 object.__apply__ = null;
28
29
30 return result;
31
32 }
33
34 }
35
36 */ 
37  
38  
39 if (!Function.prototype.apply) {  
40  
41   Function.prototype.apply = function(object, parameters) {  
42  
43     var parameterStrings = new Array();  
44  
45     if (!object) object = window;  
46  
47     if (!parameters) parameters = new Array();  
48  
49  
50     for (var i = 0; i < parameters.length; i++)  
51  
52       parameterStrings[i] = 'parameters[' + i + ']';  
53  
54  
55     object.__apply__ = this;  
56  
57     var result = eval('object.__apply__(' + parameterStrings.join(', ') + ')');  
58  
59     object.__apply__ = null;  
60  
61  
62     return result;  
63  
64   }  
65  
66 }  
view plain | print | copy to clipboard | ?

接下来是我模仿着编写的一个 Effect 的一个子类,用来实现闪烁的效果。

1 Effect.Blink = Class.create();  
2  
3 Effect.Blink.prototype = {  
4  
5   initialize: function(element, frequency) {  
6  
7     this.element = $(element);  
8  
9     this.frequency = frequency?frequency:1000;  
10  
11     this.element.effect_blink = this;  
12  
13     this.blink();  
14  
15   },  
16  
17  
18   blink: function() {  
19  
20     if (this.timer) clearTimeout(this.timer);  
21  
22     try {  
23  
24       this.element.style.visibility =  
25  
26           this.element.style.visibility == 'hidden'?'visible':'hidden';  
27  
28     } catch (e) {}  
29  
30     this.timer = setTimeout(this.blink.bind(this), this.frequency);  
31  
32    }  
33  
34 };  
view plain | print | copy to clipboard | ?

使用也很简单, 调用 new Effect.Blink(elementId) 就好了。

阅读(1036) | 评论(0) | 转发(0) |
0

上一篇:prototype 源码解读2

下一篇:阅读

给主人留下些什么吧!~~